{"record":{"id":"daa49bbae0495294","repo":"caddyserver/caddy","slug":"config-missing-unable-to-create-dev-logger-v","errorCode":null,"errorMessage":"config missing, unable to create dev logger: %v","messagePattern":"config missing, unable to create dev logger: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"context.go","lineNumber":581,"sourceCode":"// However, that is no longer necessary, as the closest module\n// most recently associated with the context will be automatically\n// assumed. To prevent a sudden breaking change, this method's\n// signature has been changed to be variadic, but we may remove\n// the parameter altogether in the future. Callers should not\n// pass in any argument. If there is valid need to specify a\n// different module, please open an issue to discuss.\n//\n// PARTIALLY DEPRECATED: The Logger(module) form is deprecated and\n// may be removed in the future. Do not pass in any arguments.\nfunc (ctx Context) Logger(module ...Module) *zap.Logger {\n\tif len(module) > 1 {\n\t\tpanic(\"more than 1 module passed in\")\n\t}\n\tif ctx.cfg == nil {\n\t\t// often the case in tests; just use a dev logger\n\t\tl, err := zap.NewDevelopment()\n\t\tif err != nil {\n\t\t\tpanic(\"config missing, unable to create dev logger: \" + err.Error())\n\t\t}\n\t\treturn l\n\t}\n\tmod := ctx.Module()\n\tif len(module) > 0 {\n\t\tmod = module[0]\n\t}\n\tif mod == nil {\n\t\treturn Log()\n\t}\n\treturn ctx.cfg.Logging.Logger(mod)\n}\n\ntype slogHandlerFactory func(handler slog.Handler, core zapcore.Core, moduleID string) slog.Handler\n\nvar (\n\tslogHandlerFactories   []slogHandlerFactory\n\tslogHandlerFactoriesMu sync.RWMutex","sourceCodeStart":563,"sourceCodeEnd":599,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/context.go#L563-L599","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nctx := caddy.Context{} // cfg == nil\nlogger := ctx.Logger()\n// after\nlogger := caddy.Log() // or provision via caddy.New() so the context carries a config","handlingStrategy":"validation","validationCode":"func safeLogger(ctx caddy.Context) *zap.Logger {\n    if ctx.cfg == nil { // no config: use the global logger instead of the dev-logger fallback\n        return caddy.Log()\n    }\n    return ctx.Logger()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["caddy","go","logging","zap","test-environment","panic"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}