You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(mcp): run_cloud_sync 409s give agents no recovery path (disabled-connection guidance swallowed; already-running has no job ID) #1403
Requested by AJ Steers (Aaron ("AJ") Steers (@aaronsteers)), from a hosted Cloud MCP failure review (Datadog LLM Obs tool spans, customer orgs only, Oct 14–16 2026).
Problem
run_cloud_sync fails with HTTP 409 in two situations, and in neither case does the agent get what it needs to recover.
1. Disabled connection: our guidance is dropped (bug)
CloudConnection.run_sync() catches a 409 on an inactive connection and raises AirbyteLibInputError with "re-enable the connection" guidance (added for #1205). But format_user_facing_error() in airbyte/mcp/_error_handling.py looks for an SDKError in the cause chain first and returns only the Cloud problem text. The agent never sees our message or guidance.
Repro on release-candidate/v1 (30775e81). I built the same exception chain run_sync() raises and passed it to format_user_facing_error():
disabled connection -> "State conflict"
Expected: Connection '<id>' is disabled (status 'inactive'), so a sync cannot be started. Re-enable the connection first (... update_cloud_connection with enabled=True), then retry.
This affects every PyAirbyte-raised error that wraps an SDKError and adds its own message or guidance, not just this one.
2. Sync already running: no job ID and no next step (guidance)
Cloud returns 409 try-again-later with "A sync is already running for: <connection_id>". The agent sees that text, but:
it doesn't get the running job's ID;
nothing tells it to watch that job with get_cloud_sync_status instead of starting another sync, or to call cancel_cloud_sync first if it really wants a restart;
the span records the error as upstream_error / fault upstream, but it is an expected state.
The docstring is only """Run a sync job on Airbyte Cloud.""".
Evidence (hosted MCP, customer orgs)
Oct 14: one customer session restarting syncs after a billing reactivation hit case 1 three times, on two connections (rc.29). The agent's next intent was "Retry restarting the ... sync after a transient conflict". It then called run_cloud_sync again on the same connection and got the same 409. That is what you'd expect if all it saw was "State conflict".
Case 2 came up 3 times in Oct 4–16, in 3 different orgs. I saw no retry loops after it, but none of those agents got a job ID.
Proposed fix
In format_user_facing_error(), when the outermost error is an AirbyteLibError with its own message or guidance, show that first and add the Cloud detail after it. Don't replace it. Add a unit test for the disabled-connection chain.
In run_sync() / run_cloud_sync, on try-again-later, look up the running job (newest-first get_previous_sync_logs(limit=1)). Then either raise an AirbyteLibInputError that includes the job ID and URL, or return a non-error "already running" result with them. Guidance: get_cloud_sync_status(connection_id, job_id=<id>) to monitor it; cancel_cloud_sync first if a restart is really wanted; don't retry run_cloud_sync.
Expand the run_cloud_sync docstring to cover both 409 cases. It should also say that after a wait=True timeout the sync keeps running, so the agent should check its status rather than start a new sync.
Correction to fix 1 above: the current behavior is intentional. AGENTS.md ("Agent-facing Cloud Error Messages") says PyAirbyte keeps the Cloud detail/title text as it is. It only adds its own guidance for actor-not-ready and 403 errors, and poor Cloud wording should be fixed in the platform.
Because of that rule, the disabled-connection guidance in CloudConnection.run_sync() (added for #1205) never reaches agents. They only see Cloud's text, "State conflict". So this isn't a simple formatting bug. There are two options:
A. Add a narrow exception to the rule: in cloud_error_guidance(), add guidance for a 409 state-conflict from the create-job route when the connection is inactive, the same way actor-not-ready guidance is handled. Then the existing run_sync() hint is either removed or relied on.
B. Fix it in the platform: return a specific problem from the public jobs API, e.g. "Connection is disabled", instead of the generic "State conflict".
Fixes 2 and 3 (job ID plus next steps for try-again-later, and the docstring) still apply. Under the same rule, fix 2 would also need to be an allowed guidance case in cloud_error_guidance(), or a non-error "already running" result.
Activity
devin-ai-integration commentedon Oct 17, 2026
Correction to fix 1 above: the current behavior is intentional.
AGENTS.md("Agent-facing Cloud Error Messages") says PyAirbyte keeps the Clouddetail/titletext as it is. It only adds its own guidance for actor-not-ready and 403 errors, and poor Cloud wording should be fixed in the platform.Because of that rule, the disabled-connection guidance in
CloudConnection.run_sync()(added for #1205) never reaches agents. They only see Cloud's text, "State conflict". So this isn't a simple formatting bug. There are two options:cloud_error_guidance(), add guidance for a409 state-conflictfrom the create-job route when the connection is inactive, the same way actor-not-ready guidance is handled. Then the existingrun_sync()hint is either removed or relied on.Fixes 2 and 3 (job ID plus next steps for
try-again-later, and the docstring) still apply. Under the same rule, fix 2 would also need to be an allowed guidance case incloud_error_guidance(), or a non-error "already running" result.Written by Devin