Skip to main content
Connector failures fall into two groups: request errors, returned immediately from the call you made, and provider failures, which happen mid-run and are reported per file.
Raw provider error messages and response bodies are never persisted or returned. What you receive is a fixed set of codes. This keeps another system’s internal detail—file names, user identities, tenant structure—out of your logs and your users’ screens.

Request errors

These come back from the call you just made. A connect_url that has expired returns 410; one that has already been used returns 404. Either way, generate a fresh one.

Provider failures

Every provider error is classified before it touches your data. The classification decides whether the run retries, fails the file, or stops. Two more are specific rather than classified:

Recovering from each

Reauthorization required

The most common one. Refresh tokens get revoked when a user changes their password, an admin removes an app, or a provider expires a grant. The connection moves to reauth_required and a connection.reauth_required event fires. Links stop; nothing is lost. Send the user through the connect flow again. Because reconnection merges into the existing connection, links resume with their ledgers and cursors intact and nothing re-imports.

Access lost

The account still works, but the linked folder does not. Someone moved it, deleted it, or removed this user’s access. The link becomes orphaned with an orphan_reason: An orphaned link will not run again. Point the user at a new folder with a fresh transfer, or delete the link.

Throttling

Backoff is automatic. The run slows down and keeps going; you do not need to do anything. For interactive browse calls, a 429 may carry Retry-After when a retry deadline is known—honor it rather than looping.
Interactive browsing and background runs share one request budget per provider account. A large sync in progress can make browsing feel slow for the same user. This is most noticeable on providers with tight rate limits—see the provider guides.

Transient failures

Retried automatically within the run. If a run ends completed_with_errors, the files that failed are in the ledger with state=failed. Re-post the same transfer to retry only those—the ledger means settled files are not touched again.

Permanent failures

The file failed and will not be retried. Read the row from GET /connectors/v1/links/{id}/objects?state=failed and surface it to the user.

What a crash does not do

Transfers are built so that an interrupted run is safe to resume:
  • Every external side effect is preceded by a persisted ledger intent, so a retry lands on the same identity instead of creating a duplicate
  • Files stream end to end and nothing buffers whole, so a large file cannot exhaust memory mid-run
  • Deleting a link soft-deletes it before cancelling its run, so an in-flight executor cannot resurrect it
You do not need to build deduplication on top of this. Re-posting a transfer is always safe.

A practical error-handling loop

  1. On run.failed, read error from the run and decide whether it is reauth, access loss, or something else
  2. On run.completed with status: "completed_with_errors", pull ?state=failed from the ledger and show the affected files
  3. On connection.reauth_required, prompt the user to reconnect—do not delete anything
  4. On link.orphaned, ask the user to reselect a folder
  5. Treat 403 installation_required as a bug in your request path, not a permissions problem

Next steps

Import & Export

Run mechanics, ledger states, and progress

Events

Full payloads for connector lifecycle events

Providers

Rate budgets and capability differences per provider