caddyserver/caddy · error
unable to parse URL pattern: %w
Error message
unable to parse URL pattern: %w
What it means
Thrown when MatchURLPattern.Provision compiles the configured pattern via urlpattern.New(pattern, baseURL, opts) and the WICG URL Pattern parser rejects it. This is a config-validation error: the pattern string (and optional base_url) must be parseable URLPattern syntax (e.g. `/books/:id`, `https://example.com/books/*`). The wrapped error from the urlpattern library explains the syntax problem.
Source
Thrown at modules/caddyhttp/urlpatternmatcher.go:67
}
}
// Provision compiles the URL pattern.
func (m *MatchURLPattern) Provision(_ caddy.Context) error {
input := m.Pattern
// A relative pattern with no base matches any origin: prefix wildcard
// protocol, host and port so only the path, search and hash are
// constrained. The port wildcard is needed because a request Host may
// carry an explicit port. Host-scoped matching stays opt-in via an
// absolute pattern or base_url.
if m.BaseURL == "" && !strings.Contains(input, "://") {
input = "*://*:*" + input
}
p, err := urlpattern.New(input, m.BaseURL, &urlpattern.Options{IgnoreCase: m.IgnoreCase})
if err != nil {
return fmt.Errorf("unable to parse URL pattern: %w", err)
}
m.compiledPattern = p
return nil
}
// Match returns true if the request matches the URL pattern.
func (m *MatchURLPattern) Match(r *http.Request) bool {
ok, _ := m.MatchWithError(r)
return ok
}
// MatchWithError returns true if the request matches the URL pattern. The
// request's origin (scheme://host) is the base against which the path is
// resolved, so an absolute pattern or base_url can match on scheme and host.
//View on GitHub (pinned to 50e54ee279)
Solutions
- Read the wrapped urlpattern error — it pinpoints the offending segment of the pattern
- Make relative patterns path-absolute: start with `/` (e.g. `/books/:id`, `/search?q=*`)
- Use `:name` for named segments and `*` only as a full-component wildcard (`/files/*`), not inside a component
- If pattern is absolute (`scheme://host/...`), drop base_url, or set base_url to a full origin like `https://example.com`
- Test the pair quickly: urlpattern.New accepts the same string as JavaScript's URLPattern, so try it in a browser console first
Example fix
# before
@url_pattern {
pattern "books/:id"
base_url "example.com"
}
# after
@url_pattern {
pattern "/books/:id"
base_url "https://example.com"
} Defensive patterns
Strategy: validation
Validate before calling
// Validate patterns before deploying config (URLPattern mirrors JS URLPattern):
func validPattern(pattern, base string) error {
in := pattern
if base == "" && !strings.Contains(in, "://") {
in = "*://*:*" + in // mirror Caddy's relative-pattern expansion
}
_, err := urlpattern.New(in, base, nil)
return err
} Try / catch
// urlpattern.New returns (nil, err) rather than panicking; always check both:
p, err := urlpattern.New(pattern, baseURL, nil)
if err != nil {
return fmt.Errorf("pattern %q rejected: %w", pattern, err)
}
use(p) Prevention
- Start relative patterns with `/` and use `:name` or full-component `*` only
- Keep a small test that compiles every url_pattern in your config at CI time
- Try the pattern in a browser console (new URLPattern) for fast feedback
When it happens
Trigger: A matcher block `@url_pattern pattern /books/{` or expression `url_pattern('/:id')` where the pattern has unmatched/invalid group syntax, a malformed base_url (e.g. `example.com` without scheme when the pattern needs one), a wildcard `*` placed where a full component is required, or invalid port/name characters. Fails at provision/validate time, before any request is matched.
Common situations: Confusing URLPattern syntax with regex or with nginx location syntax; forgetting that a relative pattern is auto-prefixed with `*://*:*` so the pattern must start with `/`; supplying a base_url with a path when the pattern is absolute; using `*` in the middle of a hostname component.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- url_pattern expects a string argument
- invalid action type
- getting matcher module '%s': %v
- matcher module '%s' is not a Caddyfile unmarshaler
- matcher module '%s' is not a request matcher
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/6c9bc1e73742733f.
Report an issue: GitHub.