caddyserver/caddy · error

provisioning header operations: %v

Error message

provisioning header operations: %v

What it means

During provisioning of the HTTP/2 server push handler, its nested HeaderConfig (header add/set/delete operations applied to push requests) failed to provision. This is a wrapper error; the underlying cause comes from headers.HeaderConfig.Provision, typically a placeholder that cannot be resolved or an invalid header-operation definition.

Source

Thrown at modules/caddyhttp/push/handler.go:70

	logger *zap.Logger
}

// CaddyModule returns the Caddy module information.
func (Handler) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "http.handlers.push",
		New: func() caddy.Module { return new(Handler) },
	}
}

// Provision sets up h.
func (h *Handler) Provision(ctx caddy.Context) error {
	h.logger = ctx.Logger()
	if h.Headers != nil {
		err := h.Headers.Provision(ctx)
		if err != nil {
			return fmt.Errorf("provisioning header operations: %v", err)
		}
	}
	return nil
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
	pusher, ok := w.(http.Pusher)
	if !ok {
		return next.ServeHTTP(w, r)
	}

	// short-circuit recursive pushes
	if _, ok := r.Header[pushHeader]; ok {
		return next.ServeHTTP(w, r)
	}

	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
	server := r.Context().Value(caddyhttp.ServerCtxKey).(*caddyhttp.Server)

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Read the '%v' tail of the message to identify the failing header operation and fix it.
  2. Validate the config with 'caddy validate --config <file>' before deploying.
  3. If the headers block is not needed for pushes, remove it; if push itself is unneeded (browsers deprecated it), drop the handler and use 103 Early Hints instead.

Example fix

# before (Caddyfile)
route {
  push {
    headers {
      set Link {http.response.header.link}*
    }
  }
}

# after
route {
  push {
    headers {
      set Link "</style.css>; rel=preload; as=style"
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// before calling Provision on the push handler
copyHeaders := make(headers.HeaderOps, len(h.Headers.Add))
if err := json.Unmarshal(headerJSON, &h); err != nil {
    return fmt.Errorf("decoding push handler config: %v", err)
}
// Provision errors surface at caddy.Run; validate config first instead:
// caddy validate --config Caddyfile

Try / catch

if err := pushHandler.Provision(ctx); err != nil {
    if strings.Contains(err.Error(), "provisioning header operations") {
        // inspect the wrapped cause before deciding: it is always a header-op config fault
        log.Printf("push header config invalid: %v", errors.Unwrap(err))
    }
    return err
}

Prevention

When it happens

Trigger: Configuring 'push' with a 'headers' block whose sub-operations (add/set/delete/replace) contain invalid header names, malformed regex replacements, or placeholders that fail to provision at startup.

Common situations: A push block copied from a rewrite or header handler where the placeholder syntax or replacement regex is invalid; upgrading Caddy versions where header-op validation became stricter; HTTP/2 push being deprecated in browsers so configs linger untested for a long time.

Related errors


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