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

  1. Map the status number: 404 = route missing, 401/403 = auth guard, 5xx = upstream failure
  2. Add or fix a route that serves the included URI with a 200 response
  3. Exempt internal includes from auth (matcher on the recursion-prevention header or a dedicated /includes/* prefix)
  4. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/ab7d48b8090376a5. Report an issue: GitHub.