Skip to content

fix(agent): walk error cause chain in image-shrink recovery helper (follow-up to #53582) - #53884

Open
r266-tech wants to merge 1 commit into
NousResearch:mainfrom
r266-tech:fix/image-recovery-cause-chain
Open

fix(agent): walk error cause chain in image-shrink recovery helper (follow-up to #53582)#53884
r266-tech wants to merge 1 commit into
NousResearch:mainfrom
r266-tech:fix/image-recovery-cause-chain

Conversation

@r266-tech

Copy link
Copy Markdown
Contributor

Follow-up to #53582.

The gap #53582 left

#53582 made error_classifier walk the __cause__/__context__ chain, so a wrapped image-dimension 400 (the common case when a provider/gateway re-wraps the SDK error) now correctly classifies as FailoverReason.image_too_large and enters image-shrink recovery.

But the recovery-side helper that decides how small to shrink — _image_error_max_dimension in conversation_loop.py — still read only the top-level exception:

for value in (error, getattr(error, "message", None), getattr(error, "body", None)):

On a wrapped error the provider's max allowed size: N pixels lives on __cause__, so the helper returned None, and the caller falls back to an 8000px cap:

image_max_dimension = _image_error_max_dimension(api_error) or 8000

So the recovery #53582 just enabled fires, but shrinks the image to the wrong ceiling, the provider re-rejects it, and the session bricks — arguably worse than before #53582, because recovery now triggers but still fails.

Fix

Walk the same cause chain in _image_error_max_dimension, depth-bounded to 5 and breaking on None/self-cycle, mirroring error_classifier._extract_status_code / _extract_error_body. Each exception in the chain is evaluated independently — the trigger terms (image + dimension + max allowed size) and the pixel ceiling must come from the same error, so a generic wrapper plus an unrelated cause can't be concatenated into a spurious match. Unwrapped errors behave exactly as before.

Scope is intentionally just this one recovery helper, so it reads as completing #53582's chain-walk on the recovery side. The sibling image-rejection matcher and retry_utils._error_text are left untouched as separate follow-ups.

Tests

tests/run_agent/test_image_shrink_recovery.py::TestImageTooLargeClassification passes, with new cases for the wrapped __cause__ path, an implicit __context__ chain, and a split-across-levels non-match (terms spread across different exceptions must not synthesize a false ceiling).

If this has already been handled via a separate patch, feel free to close — happy to defer.

Follow-up to NousResearch#53582. That PR taught error_classifier to walk the
__cause__/__context__ chain, so a *wrapped* image-dimension 400 now classifies
as FailoverReason.image_too_large. But the recovery-side helper
_image_error_max_dimension still inspected only the top-level exception, so on a
wrapped error it returned None and the caller fell back to an 8000px cap — the
image was shrunk to the wrong ceiling and the provider re-rejected it, the exact
brick NousResearch#53582 set out to fix.

Walk the same cause chain (depth-bounded to 5, breaking on None/self-cycle,
mirroring error_classifier._extract_status_code/_extract_error_body). Each
exception in the chain is evaluated independently: the trigger terms and the
pixel ceiling must come from the same error, so a generic wrapper plus an
unrelated cause can't be concatenated into a spurious match. Unwrapped errors
behave exactly as before.

Adds regression tests for the wrapped __cause__ path, an implicit __context__
chain, and the split-across-levels non-match.
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists labels Jun 28, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

Thorough fix for image-shrink recovery not finding pixel ceilings on wrapped errors (#53582). The _image_error_max_dimension helper now walks the __cause__/__context__ chain, matching the same traversal that classify_api_error already uses.

Key design points:

  • Each exception in the chain is evaluated independently — trigger terms and pixel ceiling must come from the same error
  • Depth bound of 5 matches existing _extract_status_code() traversal
  • Cycle guard (cause is current) prevents infinite loops

3 dedicated tests: wrapped error cause chain, deep context chain, cross-chain trigger term isolation.

No concerns. Ready to merge.


Reviewed by Hermes Agent

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused follow-up. The current-main gap is confirmed: agent/conversation_loop.py:82-108 only examines the outer exception, while the recovery path at agent/conversation_loop.py:2660-2667 falls back to an 8000px cap when the helper returns None.

The proposed five-level __cause__/__context__ traversal mirrors agent/error_classifier.py:1448-1487, keeps each exception level independently matched, and adds focused regression coverage for explicit causes, implicit contexts, and cross-level false positives. No substantive problems found.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants