Tencent/WeKnora · error
api-key policy declared for non-existent route(s): %s
Error message
api-key policy declared for non-existent route(s): %s
What it means
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.
Source
Thrown at internal/router/rbac.go:433
// registered with a "/" rel (gin path ".../evaluation/") would look
// missing against the normalized key (".../evaluation") even though
// the gate — which also normalizes c.FullPath() — matches it fine.
p := ri.Path
if len(p) > 1 {
p = strings.TrimRight(p, "/")
}
registered[ri.Method+" "+p] = struct{}{}
}
var missing []string
for method, paths := range g.apiKeyAuthorizer.RegisteredRoutes() {
for _, p := range paths {
if _, ok := registered[method+" "+p]; !ok {
missing = append(missing, method+" "+p)
}
}
}
if len(missing) > 0 {
panic("api-key policy declared for non-existent route(s): " + strings.Join(missing, ", "))
}
}
func (g *rbacGuards) SystemAdmin() gin.HandlerFunc {
return middleware.RequireSystemAdmin(g.cfg)
}
// Ownership-or-role guards. Required role here is the privilege level
// that bypasses the ownership check; Contributors ALWAYS pass when they
// own the resource.
// OwnedKBOrAdmin: KB mutations (update/delete/pin/copy). The original
// creator may proceed; otherwise Admin+ is required. Contributors who
// did not create the KB get 403 (when enforcement is on).
func (g *rbacGuards) OwnedKBOrAdmin() gin.HandlerFunc {
return middleware.RequireOwnershipOrRole(types.TenantRoleAdmin, g.kbCreator, g.cfg)
}
View on GitHub (pinned to 988cbb0330)
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
Example fix
// before
policy: {"POST /api/chunks/": apiKeyGuard}
// after
policy: {"POST /api/chunks": apiKeyGuard} // matches registered route without trailing slash Defensive patterns
Strategy: validation
Validate before calling
for method, p := range policies {
if _, ok := registered[method+" "+p]; !ok {
fmt.Printf("policy %s %s has no route\n", method, p)
}
}
// run: go test ./internal/router -run TestAssertAPIKeyPoliciesMatchRoutes Try / catch
func newRouterSafe(cfg Config) (engine *gin.Engine, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("router init failed: %v", r) } }()
return NewRouter(cfg), nil
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- E2BAPIKey is required for the E2B backend
- API key is required for Exa provider
- failed to generate JWT secret: %v
- im: duplicate command registration: %s
- types.TenantIDContextKey not set in context
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/1ac21a5d3c5d6b4f.
Report an issue: GitHub.