caddyserver/caddy · error
unmarshaling admin listener address from config: %v
Error message
unmarshaling admin listener address from config: %v
What it means
DetermineAdminAPIAddress unmarshals only the top-level {"admin": {...}} field of the loaded config to find admin.listen; if those bytes are not valid JSON this wrap of the json.Unmarshal error is returned. With a --adapter this should not happen (the adapter output is JSON), so it nearly always means a raw JSON file is corrupt.
Source
Thrown at cmd/commandfuncs.go:894
if len(loadedConfig) == 0 {
// get the config in caddy's native format
loadedConfig, loadedConfigFile, _, err = LoadConfig(configFile, configAdapter)
if err != nil {
return "", err
}
if loadedConfigFile == "" {
return "", fmt.Errorf("no config file to load; either use --config flag or ensure Caddyfile exists in current directory")
}
}
// get the address of the admin listener from the config
if len(loadedConfig) > 0 {
var tmpStruct struct {
Admin caddy.AdminConfig `json:"admin"`
}
err := json.Unmarshal(loadedConfig, &tmpStruct)
if err != nil {
return "", fmt.Errorf("unmarshaling admin listener address from config: %v", err)
}
if tmpStruct.Admin.Listen != "" {
return tmpStruct.Admin.Listen, nil
}
}
}
// Fallback to the default listen address otherwise
return caddy.DefaultAdminListen, nil
}
// configFileWithRespectToDefault returns the filename to use for loading the config, based
// on whether a config file is already specified and a supported default config file exists.
func configFileWithRespectToDefault(logger *zap.Logger, configFile string) (string, error) {
const defaultCaddyfile = "Caddyfile"
// if no input file was specified, try a default Caddyfile if the Caddyfile adapter is plugged in
if configFile == "" && caddyconfig.GetAdapter("caddyfile") != nil {View on GitHub (pinned to 50e54ee279)
Solutions
- Validate the JSON: jq . /path/to/config.json or caddy validate --config <file>
- Write config files atomically (write temp file, then rename) so readers never see partial content
- If using a Caddyfile or other format, pass the matching --adapter so it is converted to JSON first
Example fix
# before caddy reload --config caddy.json # file has trailing comma # after jq . caddy.json >/dev/null && caddy reload --config caddy.json
Defensive patterns
Strategy: validation
Validate before calling
// Pre-parse to catch corrupt JSON before the CLI does:
var probe struct{ Admin caddy.AdminConfig `json:"admin"` }
if err := json.Unmarshal(raw, &probe); err != nil { return fmt.Errorf("config JSON invalid: %w", err) } Prevention
- Lint generated JSON with jq before handing it to caddy
- Write configs atomically (temp file + rename)
- Pair non-JSON configs with the right --adapter
When it happens
Trigger: Passing --config pointing at a hand-edited JSON file with a typo; a truncated file (disk full, interrupted write); a JSON file with a BOM or CRLF issues that break parsing at the admin key level.
Common situations: Scripts that generate the JSON config emitting invalid JSON; editing the config in place while a reload tool concurrently reads it.
Related errors
- config is not valid JSON: %w, at offset %d; did you mean to
- config is not valid JSON: %w; did you mean to use a config a
- parsing environment file: %v
- %w, at offset %d
- invalid admin address %s: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/3410c68cade66443.
Report an issue: GitHub.