{"record":{"id":"1ac21a5d3c5d6b4f","repo":"Tencent/WeKnora","slug":"api-key-policy-declared-for-non-existent-route-s","errorCode":null,"errorMessage":"api-key policy declared for non-existent route(s): %s","messagePattern":"api-key policy declared for non-existent route\\(s\\): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/router/rbac.go","lineNumber":433,"sourceCode":"\t\t// registered with a \"/\" rel (gin path \".../evaluation/\") would look\n\t\t// missing against the normalized key (\".../evaluation\") even though\n\t\t// the gate — which also normalizes c.FullPath() — matches it fine.\n\t\tp := ri.Path\n\t\tif len(p) > 1 {\n\t\t\tp = strings.TrimRight(p, \"/\")\n\t\t}\n\t\tregistered[ri.Method+\" \"+p] = struct{}{}\n\t}\n\tvar missing []string\n\tfor method, paths := range g.apiKeyAuthorizer.RegisteredRoutes() {\n\t\tfor _, p := range paths {\n\t\t\tif _, ok := registered[method+\" \"+p]; !ok {\n\t\t\t\tmissing = append(missing, method+\" \"+p)\n\t\t\t}\n\t\t}\n\t}\n\tif len(missing) > 0 {\n\t\tpanic(\"api-key policy declared for non-existent route(s): \" + strings.Join(missing, \", \"))\n\t}\n}\n\nfunc (g *rbacGuards) SystemAdmin() gin.HandlerFunc {\n\treturn middleware.RequireSystemAdmin(g.cfg)\n}\n\n// Ownership-or-role guards. Required role here is the privilege level\n// that bypasses the ownership check; Contributors ALWAYS pass when they\n// own the resource.\n\n// OwnedKBOrAdmin: KB mutations (update/delete/pin/copy). The original\n// creator may proceed; otherwise Admin+ is required. Contributors who\n// did not create the KB get 403 (when enforcement is on).\nfunc (g *rbacGuards) OwnedKBOrAdmin() gin.HandlerFunc {\n\treturn middleware.RequireOwnershipOrRole(types.TenantRoleAdmin, g.kbCreator, g.cfg)\n}\n","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/router/rbac.go#L415-L451","documentation":"This is a startup invariant check in the router: every method+path declared in the api-key policy table must correspond to a route actually registered on the gin engine. If any policy entry has no matching route, assertAPIKeyPoliciesMatchRoutes panics listing the orphaned method+path pairs.","triggerScenarios":"Adding or editing an api-key policy entry whose path/method does not exactly match a registered route — most often a trailing-slash mismatch, wrong HTTP method, typo, or a route removed/renamed without updating the policy (seen in TestAssertAPIKeyPoliciesMatchRoutes_TrailingSlash and _Missing).","commonSituations":"Declaring policy for /api/foo/ while the route is /api/foo; changing a route from POST to PUT without updating policy; deleting a handler but leaving its policy behind; path parameter syntax differing between policy and route registration.","solutions":["Update the policy entry to exactly match the registered route's method and path (including presence/absence of trailing slash)","Remove the stale policy entry if the route no longer exists","Add the missing route registration if the policy is correct and the handler was accidentally dropped","Run the route-vs-policy test locally (TestAssertAPIKeyPoliciesMatchRoutes_*) before shipping router changes"],"exampleFix":"// before\npolicy: {\"POST /api/chunks/\": apiKeyGuard}\n// after\npolicy: {\"POST /api/chunks\": apiKeyGuard} // matches registered route without trailing slash","handlingStrategy":"validation","validationCode":"for method, p := range policies {\n    if _, ok := registered[method+\" \"+p]; !ok {\n        fmt.Printf(\"policy %s %s has no route\\n\", method, p)\n    }\n}\n// run: go test ./internal/router -run TestAssertAPIKeyPoliciesMatchRoutes","typeGuard":null,"tryCatchPattern":"func newRouterSafe(cfg Config) (engine *gin.Engine, err error) {\n    defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"router init failed: %v\", r) } }()\n    return NewRouter(cfg), nil\n}","preventionTips":["Keep policy declarations and route registrations adjacent in code so they change together","Always run the route/policy parity tests before merging router changes","Watch trailing slashes and method changes when refactoring endpoints"],"tags":["go","panic","routing","rbac","startup-validation","api-key"],"backgroundTag":"route-policy-mismatch","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}