Skip to main content

Troubleshooting: DSAR export, decrypt, and cancel failures

An access-class DSAR (request_type know or portability) runs through three operator-visible stages after the export worker finishes:
1

Cancel the request

POST /compliance/dsar/{id}/cancel withdraws a request while it is still received or processing.
2

Resolve the export location

GET /compliance/dsar/{id}/decrypted first resolves the bucket the export worker wrote the encrypted artifacts to.
3

List, download, and decrypt the artifacts

The same endpoint lists the encrypted files under the export’s object prefix, downloads each one, decrypts it, and assembles the plaintext JSON bundle (64 MB aggregate ceiling).
Each stage fails closed with a specific error.code, and — like every Orbit error — the response body still arrives in the standard envelope:
Read error.code first, then details.stage — together they name exactly which step below failed. For the happy-path lifecycle and the API shape, see Data Subject Access Requests.

Decision tree

Identify the code on the response, then jump to its section:

DSAR_BUCKET_UNCONFIGURED (500)

The decrypted download could not run because no export storage location is configured on this deployment — the bucket lookup returned nothing. Fix. Have your platform operator set one of these environment variables on the API deployment, in priority order:
  1. DEVOTEL_DSAR_BUCKET — the dedicated DSAR export bucket (preferred).
  2. DEVOTEL_GCS_PRIVATE_BUCKET — the general private-bucket fallback.
  3. DEVOTEL_GCS_AUDIT_BUCKET — the last-resort fallback.
Set exactly the bucket the export worker writes to — the mismatch is as broken as the missing variable. If you are unsure which bucket the worker uses, look at the export_url on GET /compliance/dsar/{id} — its bucket component is the value to configure. Retry-safe: yes, once the variable is set — repeat the GET /compliance/dsar/{id}/decrypted call. This is a deployment configuration gap, not a request problem, so no new DSAR request is needed.

DSAR_DECRYPT_LIST_FAILED (502)

The storage list call that enumerates the export’s encrypted files failed before any artifact was read — the storage backend was unreachable or the deployment’s service account lost its read binding on the bucket. Fix.
  1. Confirm the storage service is reachable from your deployment (a transient network or storage-control-plane blip is the common cause).
  2. Confirm the deployment’s service account still has storage-object read access on the export bucket — a revoked IAM binding or a bucket moved to a different project breaks listing before anything else.
  3. If the bucket lives in a different cloud or account than the one the listing credential can see, re-point DEVOTEL_DSAR_BUCKET at the bucket the worker actually wrote to.
Retry-safe: yes — re-issue the same GET. A retry that still fails after the network and binding checks needs operator attention on the deployment.

DSAR_DECRYPT_NO_ARTIFACTS (404)

The listing succeeded but returned no encrypted files for this DSAR — the export is gone from storage. Fix.
  1. Check GET /compliance/dsar/{id} first. If export_expires_at is in the past, the export was swept under its retention window — file a new access request to regenerate it.
  2. If the request’s status is not completed, no export was ever produced — check the worker outcome on the request row.
  3. If the request is completed and unexpired, verify you are reading the same bucket the worker wrote (the export_url’s bucket vs. DEVOTEL_DSAR_BUCKET).
Retry-safe: repeating the GET returns the same 404 while nothing has changed. The correct re-do is a new access DSAR, not a re-download.

DSAR_DECRYPT_DOWNLOAD_FAILED (502)

One specific encrypted file failed to download from storage while the bundle was being assembled — a per-object transport problem, not a configuration problem. Fix.
  1. Confirm the object path still exists — the details.artifact field on the error names the file’s logical name (for example tables/contacts.jsonl), and GET /compliance/dsar/{id} returns the object prefix the download ran under.
  2. Confirm the service account can read objects, not just list them — a binding that grants listing but not downloads fails exactly here.
  3. Retry the GET. Because failures surface per file, a transient transport fault on one artifact often succeeds on retry.
Retry-safe: yes — re-issue the GET. If the same artifact keeps failing across retries, escalate with the artifact name (see the escalation section below).

DSAR_DECRYPT_FAILED (500)

A downloaded file could not be decrypted — either the platform encryption key rotated after the export was generated (so the current key no longer matches the envelope), or the stored envelope is corrupt. Fix.
  1. If your deployment rotated its data-encryption key recently, the export predates the rotation and can no longer be opened with the current key — generate a fresh access export for the subject and download it under the current key.
  2. If no rotation happened and the failure names one artifact only while the rest decrypt, that envelope is corrupt — regenerate the export by filing a new access request, and escalate the corrupt artifact name to support (below).
  3. Do not keep retrying the same export: a malformed or mismatched envelope fails deterministically on every attempt.
Escalate recurring decrypt failures on fresh exports — that pattern indicates a key-management fault on the platform side, not anything you can fix from your tenant.

DSAR_DECRYPT_TOO_LARGE (413)

The combined decrypted export crossed the 64 MB aggregate ceiling the API enforces when assembling a bundle in a single response. This protects the API from out-of-memory failures on pathologically large subjects — it is a deliberate limit, not a fault. Fix. Fetch the export’s signed export_url from GET /compliance/dsar/{id} and open the encrypted export landing page — its per-file links let you retrieve and decrypt each artifact individually instead of pulling the whole bundle into one response. Retry-safe: retrying the bundled endpoint returns the same 413. The per-file path is the supported workaround; there is no request-side way to raise the ceiling.

DSAR_CANCEL_FAILED (500)

The cancel endpoint failed to persist the withdrawal — the database update threw before it could mark the request cancelled. Fix. Re-issue the POST /compliance/dsar/{id}/cancel call — the operation is idempotent per request id, and a transient fault that failed the first attempt usually succeeds on retry. One sibling response on the same endpoint is expected behaviour, not a failure: if the request has already reached a terminal state (completed, failed, expired, or cancelled) or never existed, the endpoint returns 409 DSAR_NOT_CANCELLABLE instead. Read the status first with GET /compliance/dsar/{id}; only a still-received or still-processing request can be cancelled within the close window. Retry-safe: yes — cancellation is retry-safe by design. If repeated attempts keep failing with 500 on a request that reads received or processing, escalate with the request id (below).

Retry safety summary


When to escalate

Escalate to support when the fix above does not clear the failure, or when a decrypt failure hits a fresh export (a platform-side key fault). Include:
  • The DSAR request id (dsar_…) from GET /compliance/dsar/{id}.
  • The error.code and error.details.stage from the response — for a download or decrypt failure, the details.artifact name; for a list failure, the details.bucket name.
  • The meta.request_id from the failing response.
Every control on this page is a tenant-owned path: Orbit exposes the export, decrypt, and cancel operations and the failure signals above; how you handle a data subject’s request — and which request type you fulfil — stays your call. Nothing here is a claim of GDPR, CCPA, or other compliance.