Skip to content

fix(client): treat any 4xx on stop as already-stopped, not an error#12

Open
derencius wants to merge 3 commits into
mainfrom
fix/cancel-workflow-tolerate-4xx
Open

fix(client): treat any 4xx on stop as already-stopped, not an error#12
derencius wants to merge 3 commits into
mainfrom
fix/cancel-workflow-tolerate-4xx

Conversation

@derencius

@derencius derencius commented May 30, 2026

Copy link
Copy Markdown
Member

Problem

cancel_workflow only treated 404/410 as "already stopped" and re-raised every other client error. The API returns 400 when a run is already in a terminal state — that escaped as a raw Faraday::BadRequestError, which isn't an OutputWorkflows::APIError, so callers that rescue APIError (e.g. cancelling a concurrent execution before dispatch) missed it and failed.

Fix

Allowlist the statuses the stop endpoint returns when a run genuinely can't be stopped — 400, 404, 409, 410 (terminal / gone / expired) — and return false for those. Every other error (401 auth, 403 forbidden, 408, 429 rate limit, 5xx, network) routes through handle_faraday_error and surfaces as OutputWorkflows::APIError, so the caller's rescue catches it instead of dying on a raw Faraday error — and real auth/quota failures aren't silently swallowed as a successful no-op.

Review

Codex review flagged an earlier "all 4xx → false" version as too aggressive (it would have masked 401/403/429). Narrowed to the allowlist per that feedback.

Testing

  • 400/404/409/410 return false; 401/403/408/429 raise APIError (TDD red/green).
  • Full client suite: 24 runs, 0 failures.

🤖 Generated with Claude Code

cancel_workflow only swallowed 404/410 and re-raised other client errors.
A 400 (run already terminal on the API) escaped as a raw
Faraday::BadRequestError, which isn't an OutputWorkflows::APIError — so a
caller that rescues APIError (e.g. cancelling a concurrent execution
before dispatch) missed it and failed.

Any 4xx on the stop call means the run can't be stopped (terminal, gone,
or expired) — functionally already stopped — so return false instead of
raising.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
derencius and others added 2 commits May 30, 2026 12:06
Codex review flagged the catch-all 4xx -> false as too aggressive: a 401
(expired auth), 403 (forbidden), 408, or 429 (rate limit) on /stop would
be silently swallowed as a successful no-op, hiding real auth/quota
failures and recording a misleading terminal local state.

Narrow to ALREADY_STOPPED_STATUSES (400/404/409/410 — the terminal/gone/
expired cases). Every other Faraday error routes through
handle_faraday_error and surfaces as OutputWorkflows::APIError, so the
caller's rescue catches it instead of dying on a raw Faraday error.

Add tests asserting 401/403/408/429 raise APIError.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The .codex-feedback--* pattern is already covered by the global
gitignore; no need for a repo-level entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant