wrap inner chunk reader error with %w to preserve errors.Is identity#4929
Open
johnelliott wants to merge 3 commits intomainfrom
Open
wrap inner chunk reader error with %w to preserve errors.Is identity#4929johnelliott wants to merge 3 commits intomainfrom
johnelliott wants to merge 3 commits intomainfrom
Conversation
d38f111 to
b0679ff
Compare
johnelliott
added a commit
that referenced
this pull request
Apr 29, 2026
…entity pkg/handlers/default.go:139 wrapped the CancellableWrite failure with %v, which dropped context.DeadlineExceeded / context.Canceled from the errors.Is chain on the returned ErrProcessingFatal. The downstream measureLatencyAndHandleErrors classifier uses errors.Is(err, context.DeadlineExceeded) to increment the timeout metric and apply the "error processing chunk" framing; with %v that branch was unreachable for this failure path, causing the timeout metric to under-count and the chunk-processing framing to be missing. Switching to %w preserves both the outer ErrProcessingFatal wrap (so isFatal still classifies correctly) and the inner ctx.Err() identity (so the timeout classifier fires). Multiple %w verbs in a single fmt.Errorf are supported on Go 1.20+; this repo is on Go 1.24. Same shape as #4929's fix at line 137 but feeds a different classifier (metric correctness rather than control flow). Adds a regression test that constructs a dead context, drives a chunk-error through handleNonArchiveContent against an unbuffered output channel to force CancellableWrite to fail, and asserts both the outer ErrProcessingFatal wrap and the inner ctx.Err() identity are preserved for both DeadlineExceeded and Canceled.
casey-tran
previously approved these changes
Apr 29, 2026
casey-tran
reviewed
Apr 29, 2026
Comment on lines
+169
to
+172
| assert.True(t, errors.Is(got[0].Err, ErrProcessingWarning), | ||
| "outer ErrProcessingWarning wrap should be preserved") | ||
| assert.True(t, errors.Is(got[0].Err, tc.innerErr), | ||
| "inner cause should be inspectable via errors.Is") |
Contributor
There was a problem hiding this comment.
Do we want to use assert.ErrorIs for these?
b0679ff to
abe0e68
Compare
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.
Summary
pkg/handlers/default.go:137wraps the inner chunk reader error with%v, which breakserrors.Isfor the wrapped cause:Go 1.20+ supports multiple
%wverbs in a singleErrorf, and this repo is on Go 1.24 (go.mod). The outerErrProcessingWarningwrap is preserved; the inner cause becomes inspectable viaerrors.Is.Why this matters
isFatal()inpkg/handlers/handlers.go:482-493classifies errors usingerrors.Is(err, context.Canceled)/errors.Is(err, context.DeadlineExceeded)/errors.Is(err, ErrProcessingFatal). With the current%vwrap, acontext.DeadlineExceededraised bychunkResult.Error()loses its identity in the chain —isFatalreturns false for it, and the error falls into the non-fatal path where the file-processing loop continues to read chunks from a reader whose context is already dead.In recent production log samples, ~71 out of 200 entries at
handlers/handlers.go:428werecontext deadline exceedederrors emitted as non-fatal warnings. With this PR they would correctly classify as fatal and terminate per-file processing on real timeouts.Behavior change
This is not purely a logging fix. Switching the wrap will cause
isFatalto return true forcontext.DeadlineExceeded(and any other previously-shadowed sentinel errors) in this code path. That changes runtime behavior:isFatalreturns true ->handleChunksWithErrorreturns the error -> per-file processing terminates immediately.This is arguably the correct behavior — once the context is cancelled, continuing to read chunks is pointless. But reviewers should confirm there are no implicit dependencies on the current "swallow-and-continue" semantics in source-specific handlers (S3, Git, Bitbucket, etc.) that would surface as new fatal errors at higher levels.
Companion PR
#4928 (one-line severity downgrade at
handlers.go:428) addresses the alert-volume problem at the call site. This PR addresses the underlying classification bug. They are independent and can land in any order:Error.Out-of-scope follow-ups (flagged for later)
pkg/handlers/default.go:139has the same pattern wrappingErrProcessingFatalwith%vforwriteErr. The fatal path returns immediately so theerrors.Isidentity is less load-bearing there, but consistency would argue for the same%wchange. Left out of this PR to keep scope tight.pkg/handlers/archive.go:openArchiveandpkg/handlers/rpm.go:107return raw errors that should be wrapped explicitly withErrProcessingWarningso the intent is documented at the source. No runtime change, but improves the class story.Test plan
errors.Is(err, context.DeadlineExceeded)returns true for a synthesized chunk-reader timeout (existing handler tests likely don't exercise this)Note
Medium Risk
Changes error-wrapping semantics in the chunk-read loop, which can change runtime control flow by causing previously-misclassified per-chunk cancellations/timeouts to terminate file processing. Risk is limited in scope but affects core handler error classification.
Overview
Fixes
defaultHandlerchunk-read error wrapping to use%wfor the inner cause, preservingerrors.Isidentity alongside the existingErrProcessingWarningwrapper.Adds a regression test ensuring wrapped chunk-reader errors remain inspectable (e.g.,
context.Canceled/context.DeadlineExceeded) and thatisFatalclassification follows the preserved inner cause.Reviewed by Cursor Bugbot for commit abe0e68. Bugbot is set up for automated code reviews on this repo. Configure here.