caddyserver/caddy · error
generating unique config ID: %v
Error message
generating unique config ID: %v
What it means
Caddy's ECH (Encrypted ClientHello) support generates a new ECH config by first allocating a unique 1-byte config ID via newECHConfigID. That helper probes the configured storage (path ech/configs/<id>) and also honors context cancellation. This error wraps any failure from that probe: a storage backend error (Exists failing) or a cancelled/shut-down context. It occurs during provisioning of tls.caddytls ECH when no usable ECH config exists yet.
Source
Thrown at modules/caddytls/ech.go:635
// must match the config provided to clients byte-for-byte. The config
// should only specify the DHKEM(X25519, HKDF-SHA256) KEM ID (0x0020), the
// HKDF-SHA256 KDF ID (0x0001), and a subset of the following AEAD IDs:
// AES-128-GCM (0x0001), AES-256-GCM (0x0002), ChaCha20Poly1305 (0x0003)."
//
// So we need to be sure we generate a config within these parameters
// so the Go TLS server can use it.
// generate a key pair
const kemChoice = hpke.KEM_X25519_HKDF_SHA256
publicKey, privateKey, err := kemChoice.Scheme().GenerateKeyPair()
if err != nil {
return echConfig{}, err
}
// find an available config ID
configID, err := newECHConfigID(ctx)
if err != nil {
return echConfig{}, fmt.Errorf("generating unique config ID: %v", err)
}
echCfg := echConfig{
PublicKey: publicKey,
Version: draftTLSESNI25,
ConfigID: configID,
RawPublicName: publicName,
KEMID: kemChoice,
CipherSuites: []hpkeSymmetricCipherSuite{
{
KDFID: hpke.KDF_HKDF_SHA256,
AEADID: hpke.AEAD_AES128GCM,
},
{
KDFID: hpke.KDF_HKDF_SHA256,
AEADID: hpke.AEAD_AES256GCM,
},
{View on GitHub (pinned to 50e54ee279)
Solutions
- Check that the configured storage module works: run caddy again and look at earlier storage errors; verify permissions/connectivity of the storage backend.
- Ensure the storage directory (default $HOME/.local/share/caddy) is writable by the Caddy user.
- If the context was cancelled (shutdown mid-start), simply restart Caddy; the error is transient.
- Clear stale ECH state (ech/configs/* in storage) if a previous partial write corrupted the ID space.
Defensive patterns
Strategy: validation
Validate before calling
// Before starting Caddy with ECH, verify the storage prefix is reachable.
func checkECHStorage(stor caddy.Storage, ctx context.Context) error {
ok, err := stor.Exists(ctx, "ech/configs")
if err != nil {
return fmt.Errorf("storage unusable for ECH: %w", err)
}
_ = ok
return nil
} Try / catch
// In Go code embedding Caddy, treat this as fatal for the config load:
if err := cfg.AutomaticHTTPS or provisioning; err != nil && strings.Contains(err.Error(), "generating unique config ID") {
log.Printf("ECH provisioning failed (storage or shutdown): %v", err)
} Prevention
- Health-check the storage backend before enabling ECH.
- Keep the Caddy data directory writable by the service user.
- Avoid config starts that are immediately cancelled; let provisioning finish.
When it happens
Trigger: Calling Provision/start of the tls app with ECH enabled (ech > on) while: (1) the storage backend errors on Exists (bad permissions, unreachable distributed storage), or (2) the caddy.Context is cancelled (shutdown during config start, timeout).
Common situations: Caddyfile/JSON config with ECH enabled and a misconfigured storage module (e.g. s3 credentials rejected, file_storage path read-only); starting many configs concurrently and one gets cancelled; upgrading storage backends so old paths are inaccessible.
Related errors
- --input is required
- storing ECH private key: %v
- storing ECH config: %v
- storing ECH config metadata: %v
- supported version must be %d: got %d
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/5060dc06fba2250a.
Report an issue: GitHub.