Skip to content

refactor(go): shared apierr error renderer - #239

Merged
rado0x54 merged 1 commit into
go-backendfrom
go-apierr
Jul 12, 2026
Merged

refactor(go): shared apierr error renderer#239
rado0x54 merged 1 commit into
go-backendfrom
go-apierr

Conversation

@rado0x54

Copy link
Copy Markdown
Owner

What

Builds the shared error-rendering package the architecture doc planned but never shipped, while the goldens still pin every shape. internal/apierr now owns the three error envelopes in the wire contract:

  • apierr.Write{error} (standard envelope)
  • apierr.WriteCode{error, code} (step-up gate, contract item F)
  • apierr.WriteOAuth{error, error_description} (mediated DCR)

Every surface renders through it: rest.writeErr and webauthn.writeErr (previously duplicate implementations) delegate; hydra's 16 error-map writeJSONStatus calls and the 4 writeDCRErr calls are migrated (helper deleted); the bearer gate's hand-concatenated {"error":...} bytes go through the renderer (keeping its WWW-Authenticate logic). Per-surface writeJSON helpers keep success payloads only — no http.Error or hand-rolled error body remains outside tests.

The point (per the review that motivated this): the post-cutover envelope convergence — folding {error} into {error, code}, item F — becomes a change to one package instead of a hunt through five.

Deliberate behavior changes (all verified against Node)

  • /mcp IP-allowlist 403 was JSON-in-text/plain via http.Error; Node sends application/json (ip-allowlist.ts:94). Now application/json — a parity fix, body unchanged.
  • Three defensive 401 branches (ws upgrade, agent-proxy upgrade, step-up principal-missing) sent plain text or text/plain JSON. All are unreachable through the real mux — the bearer gate runs first — and have no Node equivalent. Normalized to the {error} envelope and annotated as defensive.
  • Bearer-gate 401 bodies gain the trailing newline json.Encoder emits (every other envelope already had it). Goldens parse JSON, so nothing pinned changes.

Tests

  • internal/apierr/apierr_test.go pins the exact bytes (body, status, content-type) of all three envelopes, including the hydra {error}-with-200 case.
  • Full suite green: all 19 Go test packages incl. the err-* golden and parity tests, go vet, pnpm spdx:check.

Also updates docs/go-backend-architecture.md §5.5, which claimed the unified renderer "was never needed" and undercounted the render paths (it missed the two duplicate writeErrs and the text stragglers).

…ses duplicate writeErrs (rest/webauthn), hydra error maps, DCR errors, and the gate's raw 401 into three renderers; fixes /mcp allowlist 403 to application/json (Node parity) and normalizes the unreachable defensive 401s in ws/agent-proxy/step-up to the {error} shape
@rado0x54
rado0x54 merged commit 312be05 into go-backend Jul 12, 2026
20 checks passed
@rado0x54
rado0x54 deleted the go-apierr branch July 12, 2026 20:38
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