{"record":{"id":"d0646f5467369a81","repo":"caddyserver/caddy","slug":"opening-log-writer-using-v-v","errorCode":null,"errorMessage":"opening log writer using %#v: %v","messagePattern":"opening log writer using %#v: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"logging.go","lineNumber":356,"sourceCode":"\tlevelEnabler zapcore.LevelEnabler\n\tcore         zapcore.Core\n}\n\nfunc (cl *BaseLog) provisionCommon(ctx Context, logging *Logging) error {\n\tif cl.WriterRaw != nil {\n\t\tmod, err := ctx.LoadModule(cl, \"WriterRaw\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"loading log writer module: %v\", err)\n\t\t}\n\t\tcl.writerOpener = mod.(WriterOpener)\n\t}\n\tif cl.writerOpener == nil {\n\t\tcl.writerOpener = StderrWriter{}\n\t}\n\tvar err error\n\tcl.writer, _, err = logging.openWriter(cl.writerOpener)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"opening log writer using %#v: %v\", cl.writerOpener, err)\n\t}\n\n\t// set up the log level\n\tcl.levelEnabler, err = parseLevel(cl.Level)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cl.EncoderRaw != nil {\n\t\tmod, err := ctx.LoadModule(cl, \"EncoderRaw\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"loading log encoder module: %v\", err)\n\t\t}\n\t\tcl.encoder = mod.(zapcore.Encoder)\n\n\t\t// if the encoder module needs the writer to determine\n\t\t// the correct default to use for a nested encoder, we\n\t\t// pass it down as a secondary provisioning step","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/logging.go#L338-L374","documentation":"Thrown during CustomLog/BaseLog provisioning when the configured log writer module cannot be opened. Caddy loads the writer module (WriterRaw, e.g. file_writer, net_writer), then calls logging.openWriter; any failure from the writer's own open logic (file permissions, bad path, unreachable socket) surfaces wrapped here with the writer value printed via %#v.","triggerScenarios":"Provisioning a logs config whose writer fails to open: file_writer with an unwritable/read-only path or missing directory, net_writer with an unreachable address, or a custom WriterOpener whose OpenWriter returns an error.","commonSituations":"Running Caddy in a container as a non-root user while logs point at /var/log with root ownership; a path with a typo'd or non-existent parent directory; systemd unit with restrictive ReadWritePaths; switching log output to a socket that is not yet up.","solutions":["Check the wrapped error text (%v) — it names the concrete cause (permission denied, no such file or directory, connection refused).","Verify the log writer path is writable by the Caddy process user (touch the file as that user; fix ownership or chmod).","Create missing parent directories or use an absolute path that exists.","For net_writer, confirm the remote endpoint is listening and reachable from the Caddy host.","Temporarily remove the writer block to fall back to the default StderrWriter{} and confirm the rest of the config loads."],"exampleFix":"// before (caddyfile)\nlog {\n    output file /var/log/caddy/access.log\n}\n\n// after — directory exists and is writable, or use a writable path\nlog {\n    output file /home/caddy/logs/access.log\n}\n\n# shell: mkdir -p /var/log/caddy && chown caddy:caddy /var/log/caddy","handlingStrategy":"validation","validationCode":"// before loading config, verify writability of file log outputs\nimport \"os\"\n\nfunc checkLogWritable(path string) error {\n    f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)\n    if err != nil {\n        return fmt.Errorf(\"log path %s not writable: %w\", path, err)\n    }\n    return f.Close()\n}","typeGuard":null,"tryCatchPattern":"// Go: treat config-load errors as fatal, but log the wrapped cause\nif err := caddy.Load(cfg, true); err != nil {\n    if strings.Contains(err.Error(), \"opening log writer\") {\n    log.Printf(\"log writer unavailable: %v\", err)\n    }\n    return err\n}","preventionTips":["Pre-create log directories and chown them to the service user in Dockerfiles/systemd units.","Run 'caddy validate --config' in CI with the same user that runs production.","Keep log paths under directories listed as writable in systemd ReadWritePaths."],"tags":["logging","provisioning","filesystem","permissions"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}