Skip to main content

Note de langue

Lorsqu’une traduction n’est pas disponible, le contenu anglais est affiché comme solution de repli. Conservez les codes d’erreur, les chemins d’API et les blocs de code.

Troubleshooting: pending-compliance and erasure gates

A GDPR Article-17 erasure request owns the contact for the life of the request: from the moment you file it until the scheduled hard-delete runs (or you cancel), a small class of pre-write checks refuse operations against that contact. The refusal is deliberate — your own erasure request is holding the contact, not a platform verdict you need to appeal. Two error codes share that shape:
  • CONTACT_ERASURE_PENDING — an outbound send to the contact is refused while an erasure request for them is pending or executing.
  • ERASURE_COOLING_OFF_ACTIVE — a new erasure filing is refused because a pending or executing request already exists for the contact.
Both resolve one of two ways: wait for the scheduled hard-delete, or cancel the active request while it is still cancellable, then retry.

Cause table

The cooling-off window is per-tenant configurable and defaults to 7 days. While a request is pending inside it:
  • erasure-request filings, message sends, and other contact writes to that contact are refused,
  • the request stays cancellable — once the window lapses, the scheduler hard-deletes the contact and writes a per-resource audit chain, and the request is no longer cancellable.
Read a contact’s active request and its window with GET /contacts/:id/gdpr/erasure-requests — each row carries status (pending, executing, cancelled, completed) and cooling_off_ends_at.

CONTACT_ERASURE_PENDING (422)

The send pipeline checks the recipient before dispatch. A contact with a pending or executing erasure request fails that check, and the send never reaches the provider — for a campaign the recipient row is marked skipped with reason: "erasure_pending"; for a direct API send the error arrives in the standard envelope:
Fix.
  1. Cancel the erasure if the send is required — while the request is still pending, call POST /contacts/:id/gdpr/erasure-request/:requestId/cancel (an optional reason is recorded on the audit trail). Sends to the contact unblock immediately.
  2. Or wait for the window. When cooling_off_ends_at lapses, the scheduler hard-deletes the contact and writes the per-resource audit chain. After that, a send to the same address behaves as a send to an unregistered recipient.
  3. Do not retry-loop the 422. The refusal is deterministic for the life of the request — it clears only on a cancellation or on the hard-delete.
Retry-safe: yes, once resolved — the gate rejects before any send is dispatched, so nothing partial exists on the platform side to clean up. Retry the identical send after a cancel, or after the contact has been deleted.

ERASURE_COOLING_OFF_ACTIVE (409)

POST /contacts/:id/gdpr/erasure-request enforces one active erasure request per contact. A second filing lands on that uniqueness rule before anything is written, and the endpoint returns the 409 — the existing request is either still cancellable (pending) or already executing. Fix.
  1. List the contact’s requests to find the active one: GET /contacts/:id/gdpr/erasure-requests — the active row is the one with status pending or executing.
  2. If the active request is pending, cancel it with POST /contacts/:id/gdpr/erasure-request/:requestId/cancel, then re-file your new request — a corrected filing always goes through the cancel.
  3. If the active request is executing (or has completed), cancel is no longer available; the scheduled hard-delete is imminent or done — treat the conflict as already resolved and file the new request only if data for the contact still exists.
Retry-safe: an immediate retry returns the same 409 until the active request resolves; after a cancel or after the hard-delete, the same POST is accepted. No row was written on the 409, so there is nothing to roll back.

DSAR_NOT_CANCELLABLE is a different, terminal gate

DSAR_NOT_CANCELLABLE (409) is the terminal state of the cancel path — it means the request cannot be withdrawn because it does not exist or has already completed, failed, expired, or been cancelled. It is not an erasure-ownership gate like the two codes above; read the request status first with GET /compliance/dsar/:id and treat the 409 as the answer, not a retryable error. Its full recovery matrix sits on Troubleshooting: DSAR export, decrypt, and cancel failures.

Recovery summary

Every control on this page is a tenant-owned path: Orbit runs the erasure lifecycle and the pre-write gates; whether you cancel a request or wait for the cooling-off window — and how you fulfil the data subject’s request — is your call. Nothing here is a claim of GDPR, CCPA, or other compliance.