caddyserver/caddy · error
directive '%s' is not an ordered HTTP handler, so it cannot
Error message
directive '%s' is not an ordered HTTP handler, so it cannot be used here - try placing within a route block or using the order global option
What it means
buildSubroute was asked to sort a list of directives, but one directive in the list is not in the global `directive_order`. Sorting is only possible for known, ordered HTTP handlers, so the directive must appear inside an explicit `route` block (which preserves order) or be registered in the order global option.
Source
Thrown at caddyconfig/httpcaddyfile/httptype.go:1428
}
}
if len(route.MatcherSetsRaw) > 0 || len(route.HandlersRaw) > 0 {
routeList = append(routeList, route)
}
} else {
routeList = append(routeList, subroute.Routes...)
}
return routeList
}
// buildSubroute turns the config values, which are expected to be routes
// into a clean and orderly subroute that has all the routes within it.
func buildSubroute(routes []ConfigValue, groupCounter counter, needsSorting bool) (*caddyhttp.Subroute, error) {
if needsSorting {
for _, val := range routes {
if !slices.Contains(directiveOrder, val.directive) {
return nil, fmt.Errorf("directive '%s' is not an ordered HTTP handler, so it cannot be used here - try placing within a route block or using the order global option", val.directive)
}
}
sortRoutes(routes)
}
subroute := new(caddyhttp.Subroute)
// some directives are mutually exclusive (only first matching
// instance should be evaluated); this is done by putting their
// routes in the same group
mutuallyExclusiveDirs := map[string]*struct {
count int
groupName string
}{
// as a special case, group rewrite directives so that they are mutually exclusive;
// this means that only the first matching rewrite will be evaluated, and that's
// probably a good thing, since there should never be a need to do more than oneView on GitHub (pinned to 50e54ee279)
Solutions
- Wrap the directive in a `route { }` block so no ordering is inferred
- Add `order <directive> before <known>` (or after) to the global options block
- If the directive comes from a plugin, confirm the plugin registers itself in directiveOrder or check its docs for the required order line
- Verify spelling of the directive name — typos also surface here
Example fix
# before
example.com {
my_plugin_directive
}
# after
{
order my_plugin_directive before respond
}
example.com {
my_plugin_directive
} Defensive patterns
Strategy: validation
Validate before calling
// Before adapting plugin configs, verify directive is orderable
known := directiveOrderSet()
if !known[dir] && !insideRouteBlock(dir) {
return fmt.Errorf("declare order for %s or wrap in route", dir)
} Type guard
func isOrderedDirective(d string) bool {
return slices.Contains(directiveOrder, d)
} Prevention
- Wrap unknown/plugin directives in route blocks by default
- Add `order <dir> before/after <x>` to global options once per plugin
- Check plugin docs for the required order line at install time
When it happens
Trigger: Using a directive inside a context where its relative order matters and it is not in the default order list — commonly a third-party plugin directive used at site level, or a directive placed where the adapter sorts (e.g. directly in a site block) when it has no default ordering. The fix paths are exactly the message: wrap it in a `route` block or add `order <directive> before|after <other>` to the global options.
Common situations: Installing a plugin (e.g. a custom handler) and using its directive without declaring order; new directives added in newer Caddy versions while an old `order` global overrides defaults; using `handle_path`-style grouping with unknown directives.
Related errors
- encoding new config: %v
- consolidating TLS connection policies for server %d: %v
- applying global server options: %v
- server listening on %v is configured for HTTPS and cannot na
- %s (try specifying https:// in the address)
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/27dcce441a8c5b66.
Report an issue: GitHub.