Skip to main content

Troubleshooting: CRM integration sync error codes

A CRM integration on your dashboard — Salesforce, HubSpot, or a CDP destination (Braze, Iterable, Customer.io, Klaviyo) — reports a sync failure and the status stops tracking. Every failure one of these integrations raises collapses into one of three stable codes. Read error for the code first; the surface that raised it (an agent CRM tool, a queued activity-log item, an inbound contact-resolution call, or a CDP segment sync run) decides which recovery step to take.

Symptom

The integration card on Settings → Integrations reads disconnected or error, a CRM agent tool returns a { "ok": false, "error": "<code>" } result, an inbound contact-resolution call raises one of the codes, or a CDP segment sync run stamps one on its run record. The dashboard renders whichever failure the integration layer surfaced — it does not mean the CRM object never moved; it means one leg (connection, token, or dispatch) failed.
CRM integrations are fail-open: a revoked token or a down CRM endpoint never blocks an Orbit-side contact write. The failure marks the sync leg, and the failed item redrives once the connection is.

Locate the failing leg

Work top-down; the first hold tells you which route raised the code.
  1. Agent CRM tools — Salesforce / HubSpot / Zendesk / Calendly / Intercom / Google Calendar / Microsoft 365 actions an LLM picks. The dispatch endpoint classifies transport errors into exactly these three codes and returns them in the tool result body as { ok: false, error: code, message } — every CRM agent tool failure is one of the three.
  2. Inbound contact resolution — the Salesforce / HubSpot inbound resolution routes and the CDP POST /api/v1/cdp/crm-sync/run object-sync route raise the same codes when the tenant’s connection to the provider can’t be resolved or the outbound push rejects.
  3. Queued activity-log items — model / call-synthesis pipelines enqueue CRM activity-log items; when the queued dispatch can’t reach the provider endpoint, CRM_DISPATCH_FAILED is stamped on the item. A backed-up queue of these items is transport, not auth.

Owner actions by code

Reconnecting (CRM_CONNECTION_MISSING / CRM_AUTH_EXPIRED)

Both connection-class codes are cleared the same way — a re-install, once:
  1. Open Settings → Integrations and check the provider row. A connected: false row = CRM_CONNECTION_MISSING; a connected: true row that still misbehaves = CRM_AUTH_EXPIRED.
  2. Re-run the OAuth install for the provider — the owner’s new consent mints a fresh token and the code clears on the next sync. Owner/admin role required — only an admin can re-authenticate an integration’s token.
  3. Confirm the status endpoint reads connected: true and a follow-up sync completes before rejecting the next failed item as done.
Do not loop the reconnect — one re-install clears both codes. If the third install still fails, treat it as CRM_DISPATCH_FAILED and escalate with the request id (see below).

Dispatch failures (CRM_DISPATCH_FAILED)

The queued item could not dispatch because the CRM endpoint rejected or timed out:
  1. Read the underlying provider response — the log line for the failed dispatch carries the raw transport detail (HTTP status, Nango/proxy response). Identify whether it was a 4xx (a validation rejection, a rate limit, a missing field) or a 5xx/timeout (transport).
  2. Fix the cause at the provider — the permission, the field map, the rate budget — and let the queue retry. Do not overwrite the queued log item blind: an undecoded 422 will be re-stamped the same way on every re-queue.
The item you see as CRM_DISPATCH_FAILED in the run view holds the failed-at timestamp and the run id — include both when you escalate so the log line can be located.

What NOT to do

  • Do not retry a re-auth loop. Re-running the OAuth install on a timer just burns the provider’s consent rate limit and does not cure a dispatch-level failure. One re-install attempt, then escalate with the log line.
  • Do not overwrite queued log items without decoding the CRM response. Re-queueing or editing around a dispatch failure before you’ve read the underlying 4xx/5xx re-stamps the same failure — the queue redrives against the same rejection.
  • Do not treat CRM_CONNECTION_MISSING as a dispatch bug. A missing connection never recovers by retrying; re-install the integration once and the code clears.

Example payloads

CRM_CONNECTION_MISSING — agent tool result, missing connection:
CRM_AUTH_EXPIRED — agent tool result, expired/revoked token:
CRM_DISPATCH_FAILED — agent tool result, provider rejected the dispatch:
The companion status endpoint for the connection itself answers with the connected envelope — a connected: false body is the reconnect prompt, not an error:

Escalation

Bring the full failed payload plus the request id from meta.request_id on the failed envelope, the provider name, and the action slug to support@devotel.io. Say which leg failed (agent tool, inbound resolution, CDP segment sync, or queued activity item) — the log line that decodes the raw transport is found by that surface and id.