caddyserver/caddy · error
http %d
Error message
http %d
What it means
Returned by the templates module's httpInclude function when the virtual request it issued against the same server came back with an HTTP status of 400 or higher. The include is treated as failed and the numeric status is embedded in the error.
Source
Thrown at modules/caddyhttp/templates/tplcontext.go:208
defer bufPool.Put(buf)
virtReq, err := http.NewRequest("GET", uri, nil)
if err != nil {
return "", err
}
virtReq.Host = c.Req.Host
virtReq.RemoteAddr = "127.0.0.1:10000" // https://github.com/caddyserver/caddy/issues/5835
virtReq.Header = c.Req.Header.Clone()
virtReq.Header.Set("Accept-Encoding", "identity") // https://github.com/caddyserver/caddy/issues/4352
virtReq.Trailer = c.Req.Trailer.Clone()
virtReq.Header.Set(recursionPreventionHeader, strconv.Itoa(recursionCount))
vrw := &virtualResponseWriter{body: buf, header: make(http.Header)}
server := c.Req.Context().Value(caddyhttp.ServerCtxKey).(http.Handler)
server.ServeHTTP(vrw, virtReq)
if vrw.status >= 400 {
return "", fmt.Errorf("http %d", vrw.status)
}
err = c.executeTemplateInBuffer(uri, buf)
if err != nil {
return "", err
}
return buf.String(), nil
}
// funcImport parses the filename into the current template stack. The imported
// file will be rendered within the current template by calling {{ block }} or
// {{ template }} from the standard template library. If the imported file has
// no {{ define }} blocks, the name of the import will be the path
func (c *TemplateContext) funcImport(filename string) (string, error) {
bodyBuf := bufPool.Get().(*bytes.Buffer)
bodyBuf.Reset()
defer bufPool.Put(bodyBuf)View on GitHub (pinned to 50e54ee279)
Solutions
- Map the status number: 404 = route missing, 401/403 = auth guard, 5xx = upstream failure
- Add or fix a route that serves the included URI with a 200 response
- Exempt internal includes from auth (matcher on the recursion-prevention header or a dedicated /includes/* prefix)
- Fix the failing upstream handler the include points at
Example fix
# before
localhost {
templates
respond `{{ httpInclude "/partials/nav" }}` # no route for /partials/nav -> http 404
}
# after
localhost {
templates
handle /partials/nav {
respond "<nav>ok</nav>"
}
respond `{{ httpInclude "/partials/nav" }}`
} Defensive patterns
Strategy: validation
Validate before calling
# ensure included URIs have explicit 200 routes
handle /partials/* {
# serve partial content with 200
respond "..."
} Prevention
- Reserve a /partials/* namespace that always returns 200 and skips auth
- Monitor access logs of the virtual requests while developing templates
- Do not httpInclude URLs guarded by auth or prone to 404
When it happens
Trigger: {{ httpInclude "/missing" }} where /missing matches no route (404), a route protected by authentication returning 401/403, an internal handler erroring with 5xx, or a subrequest that hits a redirect loop ending in an error status.
Common situations: Including a URL not covered by any site route, including a URL guarded by basic auth or IP filters (the virtual request does not carry the client's cookies/credentials unless headers are cloned appropriately), or the included handler failing due to its own backend being down.
Related errors
- virtual request cycle
- unterminated front matter
- loading template extensions: %v
- delimiters must consist of exactly two elements: opening and
- root file system not specified
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/ab7d48b8090376a5.
Report an issue: GitHub.