fix: WrapGRPCPublic preserves error code via sanitized TError detail#582
Conversation
WrapGRPCPublic was creating a bare gRPC status with no TError details, causing UnwrapGRPC on the client side to return ERR_ERROR (9) instead of the original error code. This broke errors.Is() detection for TX_EXISTS, TX_INVALID, and SERVICE_ERROR in gRPC clients like tx-blaster. Now attaches a single sanitized TError detail (code + message only). No file paths, line numbers, function names, wrapped chains, or error data are included, preserving the security properties.
|
🤖 Claude Code Review Status: Complete Current Review: Key improvements verified:
History:
|
There was a problem hiding this comment.
Pull request overview
Updates gRPC public error wrapping so that client-side UnwrapGRPC can recover the original application error code even after sanitization, preventing gRPC clients from misclassifying specific transaction errors.
Changes:
- Attach a sanitized
TErrordetail (code + message only) inWrapGRPCPublic. - Update/add tests to validate presence of sanitized details and round-trip code preservation.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
errors/errors.go |
WrapGRPCPublic now includes a sanitized TError detail in the gRPC status. |
errors/errors_test.go |
Tests updated/added to assert sanitized detail presence and round-trip behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|



Summary
WrapGRPCPublicwas creating a bare gRPC status with noTErrordetails, causingUnwrapGRPCon the client side to always returnERR_ERROR(9) instead of the original application error code (e.g.,ERR_TX_EXISTS,ERR_TX_INVALID,ERR_TX_LOCKED)errors.Is()detection in gRPC clients like tx-blaster, causing TX_EXISTS errors to be misclassified as service errors and re-queued — creating duplicate transactionsTErrordetail containing onlyCodeandMessage— no file paths, line numbers, function names, wrapped error chains, or error data are includedProblem
The error sanitization in PR #413 introduced
WrapGRPCPublicwhich strips internal details for security. However, it also stripped theTErrorstatus detail entirely:Fix
WrapGRPCPublicnow packs a sanitizedTErrorinto the gRPC status details:The error code enum is not sensitive information. The security concern addressed by #413 was about leaking file paths, stack traces, wrapped error chains, and internal debug data — all of which remain stripped.
Error handling safety
st.WithDetailserror is handled —stis only replaced on success (if newSt, detailsErr := st.WithDetails(detail); detailsErr == nil { st = newSt })anypb.Newfailure (cannot practically happen for a simple 2-field proto) falls through to bare status (same as pre-fix behavior), which is better than returning a generic marshal error that would also lose the codeTests
Is()(matches real client behavior): tests bothIs(grpcErr, sentinel)(gRPC-wrapped path) andIs(UnwrapGRPC(grpcErr), sentinel)(propagation.Client path) for TX_LOCKED, TX_EXISTS, TX_INVALID, SERVICE_ERROR, NOT_FOUND, PROCESSING