The bug

GET /v2/iam/sets/name?code=SY7WLUPN returned 404 “record not found” on UAT but worked on DEV. The set existed in the DB.

UAT was running old code. The new /sets/name endpoint didn’t exist yet, so the parameterized route /:set_code matched first — treating "name" as the set code, ignoring ?code=, and failing the DB lookup silently.

Rule: specific routes before parameterized routes

Gin matches top-down — first match wins.

// ✅ Correct
iam.GET("/sets/name", handler.GetSetNameByCode)   // specific first
iam.GET("/sets/:set_code", handler.GetSet)         // parameterized last
 
// ❌ Wrong — /:set_code swallows /sets/name, never reached
iam.GET("/sets/:set_code", handler.GetSet)
iam.GET("/sets/name", handler.GetSetNameByCode)

Query params vs path params

GET /sets/name?code=SY7WLUPN — the ?code= query param is completely invisible to a path-param handler. It reads c.Param("set_code") from the URL segment, not c.Query("code").

Diagnosing version mismatch

If an error message looks unexpectedly raw (e.g. bare GORM error instead of your custom error), the new code probably isn’t deployed yet. Check the error message — it reveals which version is running.

See also