Skip to content

Preserve one cancellation cause on the preview branch - #3986

Merged
raphael merged 1 commit into
fix/goa-generation-planfrom
fix/grpc-cancellation-cause-preview
Sep 6, 2026
Merged

raphael merged 1 commit into
fix/goa-generation-planfrom
fix/grpc-cancellation-cause-preview

Conversation

@raphael

@raphael raphael commented Sep 6, 2026

Copy link
Copy Markdown
Member

A canceled RPC remains one failure

grpc.ContextError correlates an undecoded gRPC failure with the caller's ended context when their status codes agree. Previously it exposed the transport error and ctx.Err() as two children through Unwrap() []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-plan preview branch. Keeping that base matters: consumers already using v3.31.0-preview.5 depend on its generation APIs, which do not exist on stable v3. 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 supports errors.Is and errors.As inspection of the original transport error and its wrapped types. Explicit Is and As methods 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 calls ContextError with 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:

Automatic 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.go for the contract and grpc/context_error_test.go for the preservation cases. Every other tracked file remains identical to the preview base.

@raphael
raphael merged commit 920765e into fix/goa-generation-plan Sep 6, 2026
1 check passed
@raphael
raphael deleted the fix/grpc-cancellation-cause-preview branch September 6, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant