caddyserver/caddy · error
config missing, unable to create dev logger: %v
Error message
config missing, unable to create dev logger: %v
What it means
Context.Logger falls back to a zap development logger when the context has no config (typical in unit tests). If even zap.NewDevelopment() fails — nearly always because stderr is unavailable or zap's internal setup errors — the function panics with this message. It is rare and environmental rather than a config mistake.
Source
Thrown at context.go:581
// However, that is no longer necessary, as the closest module
// most recently associated with the context will be automatically
// assumed. To prevent a sudden breaking change, this method's
// signature has been changed to be variadic, but we may remove
// the parameter altogether in the future. Callers should not
// pass in any argument. If there is valid need to specify a
// different module, please open an issue to discuss.
//
// PARTIALLY DEPRECATED: The Logger(module) form is deprecated and
// may be removed in the future. Do not pass in any arguments.
func (ctx Context) Logger(module ...Module) *zap.Logger {
if len(module) > 1 {
panic("more than 1 module passed in")
}
if ctx.cfg == nil {
// often the case in tests; just use a dev logger
l, err := zap.NewDevelopment()
if err != nil {
panic("config missing, unable to create dev logger: " + err.Error())
}
return l
}
mod := ctx.Module()
if len(module) > 0 {
mod = module[0]
}
if mod == nil {
return Log()
}
return ctx.cfg.Logging.Logger(mod)
}
type slogHandlerFactory func(handler slog.Handler, core zapcore.Core, moduleID string) slog.Handler
var (
slogHandlerFactories []slogHandlerFactory
slogHandlerFactoriesMu sync.RWMutexView on GitHub (pinned to 50e54ee279)
Solutions
- In tests, build the Context via caddy.Context{ctx: context.Background()} with a real config, or use caddy.Log() instead
- Ensure the process has a working stderr (do not close os.Stderr; check sandbox/seccomp rules)
- Provision modules with caddy.New(caddy.Config{...}) style flows so ctx.cfg is set before logging
Example fix
// before
ctx := caddy.Context{} // cfg == nil
logger := ctx.Logger()
// after
logger := caddy.Log() // or provision via caddy.New() so the context carries a config Defensive patterns
Strategy: validation
Validate before calling
func safeLogger(ctx caddy.Context) *zap.Logger {
if ctx.cfg == nil { // no config: use the global logger instead of the dev-logger fallback
return caddy.Log()
}
return ctx.Logger()
} Prevention
- Do not hand-construct caddy.Context in production code
- In tests prefer caddy.Log() or provision a real config
- Keep os.Stderr valid; do not close it in embedded scenarios
When it happens
Trigger: Calling ctx.Logger() on a Context constructed as caddy.Context{} (cfg == nil, common in tests) on a system where zap.NewDevelopment returns an error, e.g. closed/invalid stderr or restrictive sandbox.
Common situations: Unit tests that build bare Context values; running Caddy-derived code in sandboxes (seccomp, WASM) where os.Stderr writes fail; embedding Caddy modules in another application without provisioning.
Related errors
- more than 1 module passed in
- malformed tag on field %s: %v
- missing 'namespace' key in struct tag on field %s
- unable to determine module name without inline_key when type
- unable to determine module name without inline_key because t
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/daa49bbae0495294.
Report an issue: GitHub.