fix: surface full error chain on task failure; fix index-task failure banner label - #617
Merged
leghadjeu-christian merged 3 commits intoAug 18, 2026
Conversation
`error.to_string()` on an anyhow::Error only prints the outermost
`.context(...)` message and drops everything chained underneath. A
task failing mid-indexing reported only "embedding batch 27" with no
indication of *why* — the embeddings client already builds a detailed
cause (HTTP status + response body) one level down, but it was
silently discarded before ever reaching a log line, error_detail, or
the dashboard.
Use `{error:#}` instead, mirroring the review-failure path a few
lines below which already does this correctly.
Traced via task 407bfd11-99ba-48de-9632-e91b194ac483: the runner
reported only "embedding batch 27", but the Envoy AI Gateway access
logs showed the real cause was an HTTP 400 from api.fireworks.ai on
an oversized batch (244,907 bytes, ~2x any successful batch in the
same run). This fix means the next such failure self-reports that
detail instead of requiring a manual gateway-log trace.
Contributor
❌ AI Governance check failedThis PR description is missing the following governance requirements:
Please update the PR description using the pull request template and edit the PR body to re-run the check.
|
A bare index task (target_type "repository") never attempts a review, so its failure banner shouldn't say "Review did not post: ...". Added failureNoticePrefix() to pick "Indexing failed" for those and kept "Review did not post" for pull_request/issue tasks. Also trims the previous commit's comment down to one line per review feedback.
Reword both comments to describe what the code does rather than the history of the change that introduced it.
leghadjeu-christian
deleted the
fix/surface-full-error-chain-on-task-failure
branch
August 18, 2026 09:52
This was referenced Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1. Summary
This PR changes:
services/agent-runner/src/run.rs: the terminal task-failure branch now formats the reportederror with
format!("{error:#}")instead oferror.to_string().apps/web/lib/domain/tasks.ts/apps/web/app/dashboard/runs/[id]/page.tsx: the run-detailfailure banner no longer says
"Review did not post: ..."for a bare index task (which neverattempts a review) — it now says
"Indexing failed: ..."fortarget_type: "repository"tasks,and keeps the existing
"Review did not post: ..."wording forpull_request/issuetasks.It solves two related but independent problems found while tracing a real production failure:
outermost
anyhowcontext string — e.g."embedding batch 27"— silently dropping the actualroot cause chained underneath.
"Review did not post: embedding batch 27", which ismisleading for an index-only task: there was never a review attempt to "not post" in the first
place, only a failed re-index.
2. Intent
Error chain:
anyhow::Error's plainDisplay(.to_string()/{error}) prints only theoutermost
.context(...)message.index_checkoutwraps embeddings failures with.with_context(|| format!("embedding batch {batch_idx}")), and the embeddings client itself(
services/agent-clients/src/embeddings.rs) already builds a detailed cause one level down (HTTPstatus + response body snippet for a rejected request). None of that ever reached a log line,
error_detail, or the dashboard — it was generated and then thrown away at the top ofrun_once_body. This is inconsistent with the review-failure path in the very same file(
run.rs:631), which already usesformat!("review run failed: {error:#}")for exactly thisreason.
Banner label: the run-detail page's error banner is a fixed string regardless of what kind of
task failed. An index task (
command: "index",target_type: "repository", e.g. triggered by aGitLab push with no PR involved) never invokes the review agent at all, so telling the operator
"Review did not post" when indexing itself failed is actively confusing — it points troubleshooting
in the wrong direction.
3. Scope
In Scope
run.rs's terminalRunOnceOutcome::Ran(Err(error))branch:error.to_string()→format!("{error:#}").failureNoticePrefix(task)helper intasks.tsthat picks"Indexing failed"fortarget_type: "repository"and"Review did not post"otherwise, used in both failure-bannerspots on the run-detail page.
Out of Scope
run.rs:86,98,113, the config-resolutionfailure branches) have the identical
error.to_string()pattern. Flagging, not fixing here, tokeep this diff minimal and reviewable — happy to follow up separately.
banner, which is where the misleading text was reported.
4. Verification
I verified this change by:
Commands run:
Results:
No new automated test was added for either change: the Rust branch (
run_once_body) isn'tunit-testable without mocking the entire task pipeline (checkout, indexing, review), and the
{error:#}chain behavior it relies on is already exercised byagent-clients' ownembeddings.rstest suite.failureNoticePrefixis a trivial pure string-picker with no branchinglogic worth a dedicated test beyond the typecheck/lint above.
5. Screenshots / Evidence
Traced from a real production failure: task
407bfd11-99ba-48de-9632-e91b194ac483(
adorsys/xs2a/qwac-assessor, re-index triggered by a GitLab push,target_type: "repository")failed twice, byte-identically, reporting only
error_detail: "embedding batch 27", surfaced onthe dashboard as
"Review did not post: embedding batch 27"— misleading, since this was a bareindex task with no review ever attempted.
Cross-referencing the Envoy AI Gateway access logs in Loki
(
{service_name="envoy-ai-gateway"} |= "407bfd11-99ba-48de-9632-e91b194ac483") showed the realcause the runner discarded: both attempts got HTTP
400fromapi.fireworks.aifor that batch,with a request body of 244,907 bytes (~2x any successful batch in the same run) — consistent with
one oversized chunk exceeding
qwen3-embedding-8b's 32,768-token input limit. With the error-chainfix,
error_detailwould have included that HTTP status + body directly, no gateway-logspelunking required; with the banner fix, the dashboard would have correctly read
"Indexing failed: ..."instead of pointing at a nonexistent review.6. Risk Assessment
Risk level:
Potential risks:
error_detailstrings get longer for multi-level errors.Mitigation:
error_detailstructurally — it's rendered as free text on thedashboard and logged as-is. Both changes are additive/cosmetic, no control-flow change.
7. AI Usage Declaration
AI was used for:
Human verification:
8. Reviewer Focus
Please focus your review on: