Troubleshooting
Symptom-first index of the failure modes you are most likely to hit, what each one actually means, and where the fix lives. Every entry is grounded in the platform’s real contracts — status codes, response hints, and dashboard surfaces — not folklore.
The event is accepted (202) but nothing appears in HubSpot
The 202 only means “queued”. Three causes, in order of likelihood:
- No published flow subscribes to the event type. Flows match on the
exact
(source: "event_api", event_type)pair. The send response carries ahintnaming the unmatched event types, andGET /api/v1/events/{id}/statusreportsstatus: "skipped". Fix the flow’sevent_type(or add a wildcard likeorder.*) and publish. - The flow exists only in the draft. Nothing applies until you go
through Review changes → Publish — the draft is never executed. See
draft → publish. The send-time
hintis computed against the published config, so it catches this case too. - A flow matched but a step failed. Check the per-entity
errorand step trace in/status— each entity row names the failing step and the classified error.
When the record is written but with unexpected values, use
GET /api/v1/events/{id}/verify:
it re-reads HubSpot and diffs it property-by-property against what your
published flow projects.
401 Unauthorized on /api/v1/events
The x-api-key header is missing, malformed, or the key was revoked. Keys
are connector-scoped (ps_live_...); the secret is shown once at creation.
Mint a new one from connector → Settings → API keys.
423 Locked on /api/v1/events
The connector is paused or in error: ingestion is deliberately blocked,
nothing is queued. Resume the connector from the dashboard. Pause stops both
sides — event intake and source polling.
429 Too Many Requests
The org’s monthly event quota for its tier is exhausted. The response
detail carries events_used_this_period and period_resets_at. Bulk
import requests are additionally rate-limited per org — read the
X-RateLimit-* response headers before retrying.
503 Service Unavailable
A transient infrastructure failure (ingest queue or attachment store unreachable). Nothing was enqueued — the request is safe to retry with backoff.
This is the ingest call failing. A transient failure after the event was accepted is retried by the platform on its own schedule, documented with its real numbers in Reliability: retry, failures, replay.
/status reports partial_failure
At least one entity failed, or only part of a multi-entity event synced. Read
the per-entity rows in the same response: each carries action, status,
hubspot_id, and error detail. partial_failure is also the terminal
fallback for an event past the stuck deadline that has at least one entity
already reported: the entities that never reported are counted as the gap
between entities_total and entities_done.
If the event is past the same deadline but no entity has reported at all,
/status reports delayed instead, not partial_failure: that shape means
the event is simply still sitting in a slow FIFO backlog (queue depth,
other-tenant contention), not a crash. See the hint field for how long it
has been queued, and the reference table in
GET /api/v1/events/{id}/status
for the full status ladder.
A record ended up parked, failed, or quarantined
Those are record-level states in the connector’s sync events, one row per
record, and they are distinct from the event-level /status ladder above.
The short version:
parked- a transient failure (typically a dependency that had not synced yet) used up its 5 delivery attempts without ever writing anything. Not a bug: give it time and replay it.failed- a permanent error, or a mix that includes one. A replay alone will not fix it; fix the config or the payload first.quarantined- anidentity_guardrejection: too many identity fields changed at once on an existing record, which usually means a source-side join error. Replay requires an explicitforce=true.
Nothing is lost in any of the three cases: the row carries the original
payload and a replayable flag, and
POST /api/connectors/{id}/sync-events/{event_id}/replay re-runs it against
the currently published config, so “fix, publish, replay” works. Full
semantics, retry numbers and the record-mode range replay:
Reliability: retry, failures, replay.
Syncs stopped on one flow but the rest of the connector works
A 401 / 403 (revoked token, missing OAuth scope, wrong form GUID) is
fatal rather than transient: retrying only hammers the target. After 3
consecutive fatal outcomes on the same flow, that flow’s circuit breaker
trips and it is skipped while its siblings keep syncing. Fix the credential
or the flow, then reopen it with
POST /api/connectors/{id}/flows/{flow_name}/breaker/reset. When every
enabled flow has tripped, the connector itself moves to error and ingestion
starts answering 423; setting it back to active reopens everything at
once. See
Reliability: retry, failures, replay.
The Conflicts tab is empty and you expected conflicts
Almost always correct behavior, not a broken engine:
- Under
source_wins(the default, including when theconflictsblock is absent) no detection runs at all — zero rows is the strategy working. - Under
target_wins/most_recent, only a property whose last HubSpot edit came from outside plugsync is ever arbitrated. If plugsync is the only writer, every write is conflict-free by definition.
GET /api/connectors/{id}/conflicts/count returns policy_active and
never_matched so you can confirm the policy is live without waiting for a
real conflict. Full semantics (including the source_modified_path
envelope-vs-record trap):
conflicts reference.
An outbound flow never fires
Outbound events enter through an event source (HubSpot journal, REST poller, scheduled tick, file), not through the Event API:
- Check the source exists and is enabled — a flow whose
sourcenames a missing or disabled source silently never matches. - Check the flow’s
event_typeagainst what the source actually emits (the HubSpot journal emits per-object change types; a poller emits what itsjsonpathextraction names).
See event sources.
Field mapping errors in the dashboard
The mapping editor validates against real captured payloads: every event
ingested is sampled, so the editor knows the actual shape of $.payload.*.
A mapping that references a path absent from the samples is flagged inline.
Send one representative event first, then map — see
getting started, step 5.
Draft edits seem to have no effect
By design. All writes — dashboard, AI assistant, MCP, setup scripts — land in
the draft; only an explicit human Publish from Review changes promotes
them to the workers. If publish returns a 409, someone else published since
you started editing: reset your draft or keep editing and re-review. See
draft → publish.
Still stuck?
- The CLI can pull connector status, logs, and
configs from the terminal (
plugsync --help). - Enterprise and Custom-Dedicated orgs: use your dedicated support channel.
- Anything that looks like a platform bug: contact support from the dashboard.