Preserve one cancellation cause on the preview branch - #3986
Merged
raphael merged 1 commit intoSep 6, 2026
Merged
Conversation
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.
A canceled RPC remains one failure
grpc.ContextErrorcorrelates an undecoded gRPC failure with the caller's ended context when their status codes agree. Previously it exposed the transport error andctx.Err()as two children throughUnwrap() []error. Those describe the same interrupted RPC, but a caller checking every error cause could interpret the transport child as an additional failure and report an ordinary cancellation as a shutdown failure.This is the exact two-file runtime correction from #3985, applied to the
fix/goa-generation-planpreview branch. Keeping that base matters: consumers already usingv3.31.0-preview.5depend on its generation APIs, which do not exist on stablev3. No preview generator API or behavior is removed or modified here.The private context error now unwraps to
ctx.Err()as its single cause. It still returns the exact original transport text, exposes the complete gRPC status including all details, and supportserrors.Isanderrors.Asinspection of the original transport error and its wrapped types. ExplicitIsandAsmethods retain transport inspection without representing one RPC as two independent causes.Joined failures retain their meaning
The constructor follows ordinary wrappers and single-child joins, including
errors.Join(rpcErr, nil)and nested single-child joins. It declines correlation when it encounters multiple causes, or an empty or invalid multi-error cause list, leaving the existing client error path to handle the failure.A real
errors.Join(ContextError(ctx, rpcErr), cleanupErr)therefore still exposes the independent cleanup failure and its message. The change does not broaden cancellation suppression. An active caller context, a mismatched status, or a non-gRPC error still produces no correlation; remote cancellation alone is not local cancellation.The gRPC runtime owns this representation. Generated clients still decode declared and generic service errors before checking context correlation. This diff changes no generator templates, service-error precedence, retry rules, or application shutdown policies.
Compatibility and proof
Relative to
v3.31.0-preview.5, there is no wire-format, persisted-data, exported function signature, or generator API change. No migration or coordinated deployment is needed. Rebuilding a client that already callsContextErrorwith the corrected runtime applies this change without regeneration. Code manually inspecting the private unwrap structure will intentionally see one cause;errors.Is,errors.As, and gRPC status inspection remain supported. Reverting the dependency restores the former error representation without a data migration.This PR does not merge the preview into stable, create a release tag, or change version files. It preserves the complete preview base and adds only the runtime correction and its regression tests.
Validation performed on this preview base:
go test -race -count=1 ./grpc/...make lint— zero issuesmake test— all root-module packages passedAutomatic CI on this preview-targeted PR runs Dependency Review only, which passed. The existing full-test and CodeQL workflows target
v3, not the preview branch. The full preview tests, lint, and race checks listed above were run locally, with separate independent review and focused race tests. The identical two-file stable patch in #3985 passed Linux and Windows CI and CodeQL; that does not substitute for full CI on this preview base.Tests cover cancellation and deadlines, exact text and complete status protobufs with multiple details, transport identity and typed inspection, ordinary and joined wrappers, independent failures inside and outside correlation, active contexts, and nil or malformed transport inputs. Existing generated unary and streaming client tests pass, including declared-service-error precedence. These are runtime and generated-source tests, not a new end-to-end network test.
Review
grpc/error.gofor the contract andgrpc/context_error_test.gofor the preservation cases. Every other tracked file remains identical to the preview base.