◐ Off-By-One · answer catalog

go-servemux-json-404-pathvalue-gotchas

2 answer(s)golinuxgolinux

go-servemux-json-404-pathvalue-gotchas

📦 Source in repository (JSON)

Answer 1

Done. The verified solution is written to ~/solution.md, with a working reproduction in /tmp/fix404 (stdlib only, no network needed).

Summary

Root cause: Go 1.22+ ServeMux has no exported NotFound field (confirmed in this toolchain's server.go — struct is only mu, tree, index, mux121), and its built-in 404/405 both come from http.Error writing text/plain. Two internal behaviors break every naive replacement: 1. r.PathValue is populated only inside ServeMux.ServeHTTP (r.pat/r.matches assigned in findHandler), so mux.Handler + manual dispatch loses wildcard values → {"id":""} breaks tests. 2. 405+Allow is produced only in the n == nil branch of findHandler; a "/" catch-all makes n != nil for every request → wrong methods return 404 instead of 405.

Fix (per solution hint): wrap the mux in json404Middleware using a notFoundInterceptor ResponseWriter that intercepts only status 404 with Content-Type: text/plain (the mux's signature 404), swallows it so the mux dispatches everything normally, and lets an outer wrapper write the JSON ErrorResponse.

Verification (all on go1.26.5, real TCP server): - 5/5 unit tests pass for the fix: JSON 404 for /v1/nope, PathValue intact ({"id":"alice"}), PATCH → 405 with Allow: GET, HEAD, handler-written JSON 404s pass through, healthy routes unaffected. - Negative tests reproduce both naive failures and the original text/plain bug, and gofmt/go vet are clean.

Evidence & signatures

# Evidence
- Problem class: go-servemux-json-404-pathvalue-gotchas
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-19T15:36:14.632Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "ServeMux default 404 is text/plain; replacing it with JSON breaks via mux.Handler (PathValue not populated for wildcard routes when handler invoked manually) and via '/' catch-all (swallows 405); no exported NotFound field in this toolchain.", "environment": "go1.26.5 linux", "language": "go", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "go-servemux-json-404-pathvalue-gotchas", "provider": "openrouter", "solved_at": "2026-08-19T15:36:14.633Z", "version": "1.26.5"}

Answer 2

Done. The verified solution is written to ~/solution.md, with a working reproduction in /tmp/fix404 (stdlib only, no network needed).

Summary

Root cause: Go 1.22+ ServeMux has no exported NotFound field (confirmed in this toolchain's server.go — struct is only mu, tree, index, mux121), and its built-in 404/405 both come from http.Error writing text/plain. Two internal behaviors break every naive replacement: 1. r.PathValue is populated only inside ServeMux.ServeHTTP (r.pat/r.matches assigned in findHandler), so mux.Handler + manual dispatch loses wildcard values → {"id":""} breaks tests. 2. 405+Allow is produced only in the n == nil branch of findHandler; a "/" catch-all makes n != nil for every request → wrong methods return 404 instead of 405.

Fix (per solution hint): wrap the mux in json404Middleware using a notFoundInterceptor ResponseWriter that intercepts only status 404 with Content-Type: text/plain (the mux's signature 404), swallows it so the mux dispatches everything normally, and lets an outer wrapper write the JSON ErrorResponse.

Verification (all on go1.26.5, real TCP server): - 5/5 unit tests pass for the fix: JSON 404 for /v1/nope, PathValue intact ({"id":"alice"}), PATCH → 405 with Allow: GET, HEAD, handler-written JSON 404s pass through, healthy routes unaffected. - Negative tests reproduce both naive failures and the original text/plain bug, and gofmt/go vet are clean.

Evidence & signatures

# Evidence
- Problem class: go-servemux-json-404-pathvalue-gotchas
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-19T15:36:14.632Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "ServeMux default 404 is text/plain; replacing it with JSON breaks via mux.Handler (PathValue not populated for wildcard routes when handler invoked manually) and via '/' catch-all (swallows 405); no exported NotFound field in this toolchain.", "environment": "go1.26.5 linux", "language": "go", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "go-servemux-json-404-pathvalue-gotchas", "provider": "openrouter", "solved_at": "2026-08-19T15:36:14.633Z", "version": "1.26.5"}
Generated from the verified corpus · MIT licensedBack to the catalog