crowdsecurity/crowdsec · error
failed to create router for schema ref %s: %w
Error message
failed to create router for schema ref %s: %w
What it means
After the schema validates, LoadSchema builds a route-matching router from the document (openapi3 legacyrouter.NewRouter). If the router cannot be constructed — typically duplicate or conflicting path templates that make routing ambiguous — the error is wrapped as "failed to create router for schema ref <ref>: ..." and the schema is not registered.
Source
Thrown at pkg/appsec/api_validation/api_validation.go:340
loader := openapi3.NewLoader()
rv.loaders[ref] = loader
doc, err := loader.LoadFromData([]byte(schema))
if err != nil {
return fmt.Errorf("failed to load schema %s: %w", ref, err)
}
// Is it a valid OpenAPI schema?
// TODO: look into opts, should we expose some of them to the user ?
if err := doc.Validate(loader.Context, openapi3.DisableExamplesValidation()); err != nil {
return fmt.Errorf("failed to validate schema %s: %w", ref, err)
}
rv.warnUnsupportedSecuritySchemes(ref, doc, options.OnUnsupportedSecurityScheme)
router, err := legacyrouter.NewRouter(doc)
if err != nil {
return fmt.Errorf("failed to create router for schema ref %s: %w", ref, err)
}
rv.openAPISchemas[ref] = SchemaData{
Schema: doc,
Router: router,
Options: options,
}
rv.logger.Infof("loaded schema for ref %s", ref)
return nil
}
func (rv *RequestValidator) ValidateRequest(ctx context.Context, ref string, r *http.Request) error {
schemaData, exists := rv.openAPISchemas[ref]
if !exists {
return fmt.Errorf("%w: no schema loaded for ref %s", ErrInvalidSchemaName, ref)
}
View on GitHub (pinned to 909b515798)
Solutions
- Read the wrapped router error: it names the conflicting paths — rename parameters so identical-shaped paths use the same parameter name.
- Remove or merge duplicate path entries that differ only by parameter name.
- Restructure genuinely distinct routes so their templates don't collide (e.g. '/items/by-name/{name}').
- If the spec is generated, fix the generator's path naming instead of patching the output.
Example fix
// before
paths:
/items/{id}:
get: ...
/items/{name}:
get: ... # conflicts with /items/{id}
// after
paths:
/items/{id}:
get: ... Defensive patterns
Strategy: try-catch
Validate before calling
// detect ambiguous duplicate path shapes before LoadSchema
seen := map[string]string{}
for path := range doc.Paths {
key := normalizeParams(path) // e.g. /items/{id} and /items/{name} -> /items/{}
if prev, dup := seen[key]; dup {
return fmt.Errorf("conflicting paths %q and %q", prev, path)
}
seen[key] = path
} Try / catch
if err := rv.LoadSchema(ref, schema, opts); err != nil {
if strings.Contains(err.Error(), "failed to create router") {
log.Errorf("fix conflicting path templates in %s: %v", ref, err)
}
return err
} Prevention
- Use the same parameter name for paths with identical shapes
- Don't merge multiple services' paths into a single spec blindly
- Build the router in a test (legacyrouter.NewRouter) as part of CI
When it happens
Trigger: Loading a spec whose paths contain duplicate route patterns (e.g. '/items/{id}' and '/items/{name}' — same shape, different parameter names), which legacyrouter rejects as ambiguous.
Common situations: Merged/auto-generated specs where two path entries differ only in parameter name; generated clients emitting conflicting routes; concatenating specs from multiple services into one document.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- invalid schema name
- authorization header not found
- auth token is required but not provided
- ref cannot be empty
- unknown body decoder %q
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/d646941ff30a2ad3.
Report an issue: GitHub.