{"record":{"id":"5060dc06fba2250a","repo":"caddyserver/caddy","slug":"generating-unique-config-id-v","errorCode":null,"errorMessage":"generating unique config ID: %v","messagePattern":"generating unique config ID: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/ech.go","lineNumber":635,"sourceCode":"\t// must match the config provided to clients byte-for-byte. The config\n\t// should only specify the DHKEM(X25519, HKDF-SHA256) KEM ID (0x0020), the\n\t// HKDF-SHA256 KDF ID (0x0001), and a subset of the following AEAD IDs:\n\t// AES-128-GCM (0x0001), AES-256-GCM (0x0002), ChaCha20Poly1305 (0x0003).\"\n\t//\n\t// So we need to be sure we generate a config within these parameters\n\t// so the Go TLS server can use it.\n\n\t// generate a key pair\n\tconst kemChoice = hpke.KEM_X25519_HKDF_SHA256\n\tpublicKey, privateKey, err := kemChoice.Scheme().GenerateKeyPair()\n\tif err != nil {\n\t\treturn echConfig{}, err\n\t}\n\n\t// find an available config ID\n\tconfigID, err := newECHConfigID(ctx)\n\tif err != nil {\n\t\treturn echConfig{}, fmt.Errorf(\"generating unique config ID: %v\", err)\n\t}\n\n\techCfg := echConfig{\n\t\tPublicKey:     publicKey,\n\t\tVersion:       draftTLSESNI25,\n\t\tConfigID:      configID,\n\t\tRawPublicName: publicName,\n\t\tKEMID:         kemChoice,\n\t\tCipherSuites: []hpkeSymmetricCipherSuite{\n\t\t\t{\n\t\t\t\tKDFID:  hpke.KDF_HKDF_SHA256,\n\t\t\t\tAEADID: hpke.AEAD_AES128GCM,\n\t\t\t},\n\t\t\t{\n\t\t\t\tKDFID:  hpke.KDF_HKDF_SHA256,\n\t\t\t\tAEADID: hpke.AEAD_AES256GCM,\n\t\t\t},\n\t\t\t{","sourceCodeStart":617,"sourceCodeEnd":653,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/ech.go#L617-L653","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before starting Caddy with ECH, verify the storage prefix is reachable.\nfunc checkECHStorage(stor caddy.Storage, ctx context.Context) error {\n    ok, err := stor.Exists(ctx, \"ech/configs\")\n    if err != nil {\n        return fmt.Errorf(\"storage unusable for ECH: %w\", err)\n    }\n    _ = ok\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// In Go code embedding Caddy, treat this as fatal for the config load:\nif err := cfg.AutomaticHTTPS or provisioning; err != nil && strings.Contains(err.Error(), \"generating unique config ID\") {\n    log.Printf(\"ECH provisioning failed (storage or shutdown): %v\", err)\n}","preventionTips":["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."],"tags":["tls","ech","storage","provisioning"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}