caddyserver/caddy · error

loading log writer module: %v

Error message

loading log writer module: %v

What it means

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.

Source

Thrown at logging.go:346

	WithCallerSkip int `json:"with_caller_skip,omitempty"`

	// If not empty, the log entry will include a stack trace
	// for all logs at the given level or higher. See `level`
	// for possible values. Default off.
	WithStacktrace string `json:"with_stacktrace,omitempty"`

	writerOpener WriterOpener
	writer       io.WriteCloser
	encoder      zapcore.Encoder
	levelEnabler zapcore.LevelEnabler
	core         zapcore.Core
}

func (cl *BaseLog) provisionCommon(ctx Context, logging *Logging) error {
	if cl.WriterRaw != nil {
		mod, err := ctx.LoadModule(cl, "WriterRaw")
		if err != nil {
			return fmt.Errorf("loading log writer module: %v", err)
		}
		cl.writerOpener = mod.(WriterOpener)
	}
	if cl.writerOpener == nil {
		cl.writerOpener = StderrWriter{}
	}
	var err error
	cl.writer, _, err = logging.openWriter(cl.writerOpener)
	if err != nil {
		return fmt.Errorf("opening log writer using %#v: %v", cl.writerOpener, err)
	}

	// set up the log level
	cl.levelEnabler, err = parseLevel(cl.Level)
	if err != nil {
		return err
	}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Use exact writer names: 'stderr', 'stdout', 'file', 'net'.
  2. Match field names to the writer's schema (filename, roll_size_mb, etc. for file).
  3. For custom/xcaddy builds, verify the writer module is registered in the binary you run.
  4. Validate with 'caddy validate --config <file>' after edits.

Example fix

// before
"writer": { "output": "Stdout" }
// after
"writer": { "output": "stdout" }
Defensive patterns

Strategy: type-guard

Validate before calling

var knownWriters = map[string]bool{"stderr": true, "stdout": true, "file": true, "net": true, "discard": true}

func writerKnown(w map[string]any) bool {
    out, _ := w["output"].(string)
    return knownWriters[out]
}

Type guard

func isValidWriterJSON(raw json.RawMessage) bool {
    var w struct{ Output string `json:"output"` }
    if err := json.Unmarshal(raw, &w); err != nil { return false }
    switch w.Output {
    case "stderr", "stdout", "file", "net", "discard":
        return true
    }
    return false
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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