caddyserver/caddy · error
storing ECH config metadata: %v
Error message
storing ECH config metadata: %v
What it means
Final of three storage writes for a new ECH config: meta.json (creation timestamp) under ech/configs/<configID>/. A failure leaves the config ID half-populated (key.bin and config.bin present, meta.json missing). The config-creation routine returns the error, so ECH is not enabled for this start; the stranded files are ignored on later runs except that the ID is considered taken.
Source
Thrown at modules/caddytls/ech.go:688
}
metaBytes, err := json.Marshal(meta)
if err != nil {
return echConfig{}, fmt.Errorf("marshaling ECH config metadata: %v", err)
}
parentKey := path.Join(echConfigsKey, strconv.Itoa(int(configID)))
keyKey := path.Join(parentKey, "key.bin")
configKey := path.Join(parentKey, "config.bin")
metaKey := path.Join(parentKey, "meta.json")
if err := ctx.Storage().Store(ctx, keyKey, privKeyBytes); err != nil {
return echConfig{}, fmt.Errorf("storing ECH private key: %v", err)
}
if err := ctx.Storage().Store(ctx, configKey, echConfigBytes); err != nil {
return echConfig{}, fmt.Errorf("storing ECH config: %v", err)
}
if err := ctx.Storage().Store(ctx, metaKey, metaBytes); err != nil {
return echConfig{}, fmt.Errorf("storing ECH config metadata: %v", err)
}
echCfg.privKeyBin = privKeyBytes
echCfg.configBin = echConfigBytes // this contains the public key
echCfg.meta = meta
return echCfg, nil
}
// ECH represents an Encrypted ClientHello configuration.
//
// EXPERIMENTAL: Subject to change.
type ECHConfiguration struct {
// The public server name (SNI) that will be used in the outer ClientHello.
// This should be a domain name for which this server is authoritative,
// because Caddy will try to provision a certificate for this name. As an
// outer SNI, it is never used for application data (HTTPS, etc.), but it
// is necessary for enabling clients to connect securely in some cases.View on GitHub (pinned to 50e54ee279)
Solutions
- Inspect the wrapped storage error (it names the real cause) and fix the backend.
- Restart Caddy to retry provisioning with a new config ID.
- Clean up partial ech/configs/<id> directories missing meta.json to reclaim IDs if the 256-ID space ever fills.
- Stabilize the storage layer (disk space, network, credentials) before re-enabling ECH.
Defensive patterns
Strategy: retry
Try / catch
if err != nil && strings.Contains(err.Error(), "storing ECH config metadata") {
// final write failed; retry provisioning after storage repair
} Prevention
- Ensure storage consistency (disk space, network) across all three writes.
- Clean partial ECH config dirs during maintenance to reclaim the 256-ID space.
When it happens
Trigger: ctx.Storage().Store for meta.json fails after two prior successful writes — transient storage errors, disk-full occurring mid-sequence, remote storage timeout.
Common situations: Same class as the other ECH store failures: intermittent remote storage, quota exhaustion between writes, container filesystem issues.
Related errors
- storing ECH config: %v
- generating unique config ID: %v
- storing ECH private key: %v
- supported version must be %d: got %d
- depleted attempts to find an available config_id
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/51c56e523a815b2c.
Report an issue: GitHub.