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

  1. Update the policy entry to exactly match the registered route's method and path (including presence/absence of trailing slash)
  2. Remove the stale policy entry if the route no longer exists
  3. Add the missing route registration if the policy is correct and the handler was accidentally dropped
  4. 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

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


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/1ac21a5d3c5d6b4f. Report an issue: GitHub.