caddyserver/caddy · error
%v; additionally, restoring old config: %v
Error message
%v; additionally, restoring old config: %v
What it means
While indexing the new config's @id fields (indexConfigObjects), a failure occurred, and the recovery path tried to restore the previous config by unmarshaling the stored rawCfgJSON — which also failed. This compound error reports both the original indexing error and the restore failure; the in-memory raw config may now be inconsistent with the running config until the next successful load.
Source
Thrown at caddy.go:233
Err: fmt.Errorf("encoding new config: %v", err),
}
}
// if nothing changed, no need to do a whole reload unless the client forces it
if !forceReload && bytes.Equal(rawCfgJSON, newCfg) {
Log().Info("config is unchanged")
return errSameConfig
}
// find any IDs in this config and index them
idx := make(map[string]string)
err = indexConfigObjects(rawCfg[rawConfigKey], "/"+rawConfigKey, idx)
if err != nil {
if len(rawCfgJSON) > 0 {
var oldCfg any
err2 := json.Unmarshal(rawCfgJSON, &oldCfg)
if err2 != nil {
err = fmt.Errorf("%v; additionally, restoring old config: %v", err, err2)
}
rawCfg[rawConfigKey] = oldCfg
} else {
rawCfg[rawConfigKey] = nil
}
return APIError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("indexing config: %v", err),
}
}
// load this new config; if it fails, we need to revert to
// our old representation of caddy's actual config
err = unsyncedDecodeAndRun(newCfg, true)
if err != nil {
if len(rawCfgJSON) > 0 {
// restore old config state to keep it consistent
// with what caddy is still running; we need toView on GitHub (pinned to 50e54ee279)
Solutions
- Read both messages: the first is the indexing failure (duplicate/invalid @id), the second the restore failure.
- Fix the @id problem in the submitted config (uniqueness, string/number values).
- Restart Caddy from a known-good config file to rebuild consistent in-memory state — the process may hold a mutated rawCfg.
- Audit any custom code that touches rawCfg/rawCfgJSON, as stock Caddy cannot produce the second failure.
Defensive patterns
Strategy: try-catch
Try / catch
if err := postLoad(cfg); err != nil && strings.Contains(err.Error(), "additionally, restoring old config") {
// both the change AND rollback failed: state is suspect
log.Fatal("config index + rollback failed; restart Caddy from file")
} Prevention
- Do not manipulate caddy's rawCfg/rawCfgJSON from plugins.
- Fix @id errors at the source (see errors 69/72/73) — they are what trigger this path.
- Monitor admin API errors in CI config pushes to catch compound failures early.
When it happens
Trigger: A config change whose @id handling fails (duplicate IDs, wrong @id type) while the previously stored encoded config has become unmarshalable — essentially only possible when rawCfgJSON was corrupted by faulty custom code, since it was produced by json.Marshal. Returned as the inner error of the 'indexing config' APIError.
Common situations: Forked Caddy or plugins manipulating rawCfgJSON/rawCfg directly; memory corruption-class bugs; practically unreachable in stock Caddy. Seeing it means both the change and the rollback path are broken.
Related errors
- indexing config: %v
- %s: %s field must be a string or number
- duplicate ID '%s' found at %s and %s
- unknown object ID '%s'
- decoding request body: %w, at offset %d
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/eb4877cf1c19371b.
Report an issue: GitHub.