{"record":{"id":"e25aae591ba4eba8","repo":"caddyserver/caddy","slug":"loading-log-writer-module-v","errorCode":null,"errorMessage":"loading log writer module: %v","messagePattern":"loading log writer module: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"logging.go","lineNumber":346,"sourceCode":"\tWithCallerSkip int `json:\"with_caller_skip,omitempty\"`\n\n\t// If not empty, the log entry will include a stack trace\n\t// for all logs at the given level or higher. See `level`\n\t// for possible values. Default off.\n\tWithStacktrace string `json:\"with_stacktrace,omitempty\"`\n\n\twriterOpener WriterOpener\n\twriter       io.WriteCloser\n\tencoder      zapcore.Encoder\n\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","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/logging.go#L328-L364","documentation":"BaseLog.provisionCommon loads the writer module from the log's WriterRaw JSON. If ctx.LoadModule fails — unknown module ID in the writer object, malformed JSON shape for the module, or the module not compiled in — this error is returned. It is the common root cause wrapped by the 'setting up ... log' errors above.","triggerScenarios":"Any log (sink, default, or custom) with \"writer\": { \"output\": \"unknown_thing\" } or extra/missing fields that make module provisioning fail; using a writer namespace that exists only in non-standard builds.","commonSituations":"Typos in 'output' values ('stdout ' with space, 'Stdout' capitalized); JSON configs referencing third-party writers not registered in the binary; version drift where writer module names or schemas changed.","solutions":["Use exact writer names: 'stderr', 'stdout', 'file', 'net'.","Match field names to the writer's schema (filename, roll_size_mb, etc. for file).","For custom/xcaddy builds, verify the writer module is registered in the binary you run.","Validate with 'caddy validate --config <file>' after edits."],"exampleFix":"// before\n\"writer\": { \"output\": \"Stdout\" }\n// after\n\"writer\": { \"output\": \"stdout\" }","handlingStrategy":"type-guard","validationCode":"var knownWriters = map[string]bool{\"stderr\": true, \"stdout\": true, \"file\": true, \"net\": true, \"discard\": true}\n\nfunc writerKnown(w map[string]any) bool {\n    out, _ := w[\"output\"].(string)\n    return knownWriters[out]\n}","typeGuard":"func isValidWriterJSON(raw json.RawMessage) bool {\n    var w struct{ Output string `json:\"output\"` }\n    if err := json.Unmarshal(raw, &w); err != nil { return false }\n    switch w.Output {\n    case \"stderr\", \"stdout\", \"file\", \"net\", \"discard\":\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Use exact lowercase writer names from the docs.","In xcaddy builds, assert required writer modules are registered before shipping configs."],"tags":["logging","writer","module","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}