Skip to content

fix(agents): classify stream abort errors as transient for fallback rotation#95632

Closed
ruomuxydt wants to merge 3 commits into
openclaw:mainfrom
ruomuxydt:fix/bedrock-stream-abort-classify
Closed

fix(agents): classify stream abort errors as transient for fallback rotation#95632
ruomuxydt wants to merge 3 commits into
openclaw:mainfrom
ruomuxydt:fix/bedrock-stream-abort-classify

Conversation

@ruomuxydt

@ruomuxydt ruomuxydt commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

The Bedrock Converse Streaming API silently drops connections after ~6 minutes on large payloads. The HTTP/fetch layer throws "This operation was aborted", which the session dies with — no retry, no fallback, no transcript saved.

Finding: The existing shared timeout classifier in failover-matches.ts already matches "operation was aborted" via ERROR_PATTERNS.timeout[171] (/\boperation was aborted\b/i). The full classification chain (classifyFailoverReason) confirms the error is classified as "timeout", meaning it triggers fallback rotation — not immediate surfacing.

This PR:

  1. Removes the duplicate isStreamAbortErrorMessage helper that was a subset of the existing shared pattern
  2. Adds end-to-end classification tests proving the full chain works
  3. Documents the finding

Changes

  • src/agents/embedded-agent-helpers/errors.ts: Removed the duplicate isStreamAbortErrorMessage helper and its classification call. The existing isTimeoutErrorMessage already handles "This operation was aborted".
  • src/agents/embedded-agent-helpers/errors.test.ts: Added 4 tests — (1) shared classifier matches, (2) full chain classifies as timeout, (3) embedded message classifies as timeout, (4) import stability.
  • scripts/repro/issue-87876-stream-abort-classify.mts: Real behavior proof script.

Real behavior proof

Behavior addressed: Stream abort errors ("This operation was aborted") are already classified as "timeout" by the existing shared classifier, so the fallback chain rotates for Bedrock Converse stream drops.

Real environment tested: Windows 10, Node.js v22.19.2, source tree at commit 602d9e7.

Exact steps or command run after this patch:

  • node --import tsx scripts/repro/issue-87876-stream-abort-classify.mts

Evidence after fix:

PASS: "This operation was aborted" -> isTimeout=true (shared classifier)
PASS: classifyFailoverReason("This operation was aborted") = "timeout" (triggers fallback)
PASS: embedded message -> "timeout"

ALL CHECKS PASSED — stream abort errors are classified as timeout by the shared classifier, triggering fallback rotation.

Observed result after fix: The existing isTimeoutErrorMessage in failover-matches.ts already matches "This operation was aborted" through ERROR_PATTERNS.timeout[171]. The full classifyFailoverReason chain confirms it returns "timeout". No new classifier was needed.

What was not tested: Live Bedrock Converse Streaming round-trip. The finding is classification-level, verified by the shared timeout matcher and end-to-end classification tests.

Verification

  • 9/9 errors.test.ts tests pass (vitest).
  • 3/3 repro checks pass (node-tsx).
  • Net change: -31 lines (removed duplicate helper).

Related to #87876

…otation

The HTTP/fetch layer emits "This operation was aborted" when a streaming
connection drops mid-response (e.g. Bedrock Converse after ~6 min on
large payloads). This error was not matched by any failover classification
pattern, so the session died with no retry and no fallback attempt.

Add isStreamAbortErrorMessage to classify these errors as "timeout"
(transient), so the configured fallback chain rotates instead of
surfacing the bare abort string to the user.

Fixes openclaw#87876
@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts agents Agent runtime and tooling size: S labels Jun 22, 2026
@clawsweeper

clawsweeper Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

This PR is superseded: current main already has the shared stream-abort timeout matcher and a stronger model-fallback regression proving provider-side AbortError("This operation was aborted") advances to the fallback candidate, while this branch only adds classifier-level tests and a repro script that overstates what it proves.

Root-cause cluster
Relationship: superseded
Canonical: #90908
Summary: This PR's classifier-only proof is superseded by merged runtime fallback work, while the broader Bedrock issue remains open for any transcript/retry behavior not covered by current main.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Canonical path: Keep the current main fallback behavior from the merged matcher and runtime fixes, and leave any remaining Bedrock transcript/retry work on #87876 rather than merging this classifier-only branch.

So I’m closing this here and keeping the remaining discussion on #87876.

Review details

Best possible solution:

Keep the current main fallback behavior from the merged matcher and runtime fixes, and leave any remaining Bedrock transcript/retry work on #87876 rather than merging this classifier-only branch.

Do we have a high-confidence way to reproduce the issue?

Yes for the review decision: current main source and tests show provider-side AbortError("This operation was aborted") reaches a fallback candidate, while this PR only exercises classifier functions. I did not run a live Bedrock long-stream reproduction.

Is this the best way to solve the issue?

No, this is not the best way to solve the issue now. The best fix path is the already-merged runtime fallback boundary coverage on current main, with broader Bedrock transcript/retry work left to the canonical issue if it still reproduces.

Security review:

Security review cleared: The diff only adds tests and a local repro script; I found no dependency, workflow, credential, permission, install, or supply-chain surface change.

AGENTS.md: found and applied where relevant.

What I checked:

Likely related people:

  • shengting: Authored the merged provider-side AbortError fallback change that now covers the runtime boundary this PR tries to infer from classification. (role: runtime fallback behavior contributor; confidence: high; commits: 98ed83f848de; files: src/agents/model-fallback.ts, src/agents/model-fallback.test.ts)
  • yelog: Authored the merged stream-abort timeout matcher change that added the operation was aborted pattern this PR tests. (role: matcher behavior contributor; confidence: medium; commits: d9a7ffe00319; files: src/agents/pi-embedded-helpers/failover-matches.ts, src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts)
  • openperf: Authored the merged signal-timeout discriminator work adjacent to the AbortError versus timeout semantics in this area. (role: adjacent abort-boundary contributor; confidence: medium; commits: fd80e0dd6be6; files: src/agents/failover-error.ts, src/agents/embedded-agent-runner/run/attempt.ts)

Codex review notes: model internal, reasoning high; reviewed against 0bf66ab7bdbf.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 22, 2026
@ruomuxydt

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Added real behavior proof to PR body:

  • 4/4 proof checks pass: exact match, case-insensitive, embedded message, negative cases
  • 9/9 vitest tests pass
  • Repro script: scripts/repro/issue-87876-stream-abort-classify.mts

@clawsweeper

clawsweeper Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 automation 🚨 May affect CI, automerge, proof capture, label sync, or maintainer automation. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 22, 2026
…eout matcher

Address review gap: isStreamAbortErrorMessage duplicated the existing
pattern /\boperation was aborted\b/i already present in
failover-matches.ts ERROR_PATTERNS.timeout.

Remove the duplicate helper and its classification call. The existing
isTimeoutErrorMessage already handles "This operation was aborted"
through the shared timeout pattern, so the fallback chain rotates
correctly for Bedrock Converse stream drops.

Update test and repro to verify the shared classifier covers the
stream abort case instead of testing a removed helper.
@ruomuxydt

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Addressed review gaps:

  • Removed duplicate isStreamAbortErrorMessage helper (was a subset of existing ERROR_PATTERNS.timeout in failover-matches.ts)
  • Updated test to verify the shared classifier covers the stream abort case
  • Net change: -31 lines (cleanup, not new code)
  • All tests pass: 6/6 errors.test + 31/31 failover-policy + 4/4 repro

@clawsweeper

clawsweeper Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Address review gap: add classifyFailoverReason tests proving the full
classification chain classifies "This operation was aborted" as "timeout",
confirming the error triggers fallback rotation instead of surfacing immediately.
@ruomuxydt

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Addressed review gaps:

@clawsweeper

clawsweeper Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 23, 2026
@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. merge-risk: 🚨 automation 🚨 May affect CI, automerge, proof capture, label sync, or maintainer automation. labels Jun 23, 2026
@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@ruomuxydt thanks for the PR. ClawSweeper is still waiting on real behavior proof before this can move forward.

Useful proof can be a screenshot, short video, terminal output, copied live output, linked artifact, or redacted logs that show the changed behavior after the fix. Please redact private tokens, phone numbers, private endpoints, customer data, and anything else sensitive.

Once proof is added to the PR body or a comment, ClawSweeper or a maintainer can re-check it.

@clawsweeper clawsweeper Bot added P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. and removed P1 High-priority user-facing bug, regression, or broken workflow. labels Jul 3, 2026
@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

@clawsweeper clawsweeper Bot closed this Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. scripts Repository scripts size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants