feat: add PlatformCode field to Err for domain-level error identity #1
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
xerrors.Errcurrently carries aCode(e.g.ErrNotFound,ErrInvalidInput) that maps to transport-layer status codes — HTTP 404, gRPCNOT_FOUND, etc. This is intentional and should not change.However, as consumer applications grow multi-language frontends, there is a need for a second, independent error identity that operates at the platform/domain layer rather than the transport layer.
The problem
An HTTP 404 can mean many different things depending on context:
A transport code (
NOT_FOUND→ 404) cannot distinguish between these. A frontend consuming the API cannot render a specific, actionable translated message — it can only show a generic fallback.The same applies to 400s:
All map to
ErrInvalidInput/ErrAlreadyExistsat the transport layer, but each needs a distinct user-facing message in the consuming application.Why not reuse
CodeCodeis intentionally transport-agnostic in the sense that it drives status code mapping:ErrNotFound→ 404ErrNotFound→codes.NotFoundIt must remain stable and bounded. Adding domain-specific values to it would pollute the transport mapping and break the clean separation between infrastructure concerns and business concerns.
Proposed solution
Add an optional
PlatformCode stringfield toErrwith aWithPlatformCode(code string) *Errbuilder method.Behaviour
PlatformCodeis optional — not every error needs one. Internal errors, panics, and infrastructure failures do not benefit from platform codes (a 500 is always a generic "try again" regardless of cause).PlatformCodeis transport-agnostic — HTTP serializes it as"platformCode"in the JSON body; gRPC passes it in the error detail. The field travels unchanged across transports.PlatformCodedoes not affectCoderesolution or status code mapping in any way.Expected JSON response shape (HTTP consumer)
The frontend team maintains their own dictionary mapping
platformCode→ translated user message. The backend stays in English throughout.Acceptance criteria
Errhas aplatformCode stringprivate fieldWithPlatformCode(code string) *Errbuilder returns the same*Errfor chainingPlatformCode() stringgetter returns the value (empty string if not set)Code,Error,WithContextbehaviour unchangedWithContext, empty default