{"record":{"id":"ebf6b93d75641def","repo":"caddyserver/caddy","slug":"output-is-required","errorCode":null,"errorMessage":"--output is required","messagePattern":"--output is required","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/storagefuncs.go","lineNumber":144,"sourceCode":"\t\terr = stor.Store(ctx, hdr.Name, b)\n\t\tif err != nil {\n\t\t\treturn caddy.ExitCodeFailedQuit, fmt.Errorf(\"reading archive: %v\", err)\n\t\t}\n\t}\n\n\tfmt.Println(\"Successfully imported storage\")\n\treturn caddy.ExitCodeSuccess, nil\n}\n\nfunc cmdExportStorage(fl Flags) (int, error) {\n\texportStorageCmdConfigFlag := fl.String(\"config\")\n\texportStorageCmdOutputFlag := fl.String(\"output\")\n\n\tif exportStorageCmdConfigFlag == \"\" {\n\t\treturn caddy.ExitCodeFailedStartup, errors.New(\"--config is required\")\n\t}\n\tif exportStorageCmdOutputFlag == \"\" {\n\t\treturn caddy.ExitCodeFailedStartup, errors.New(\"--output is required\")\n\t}\n\n\t// extract storage from config if possible\n\tstorageCfg, err := determineStorage(exportStorageCmdConfigFlag, \"\")\n\tif err != nil {\n\t\treturn caddy.ExitCodeFailedStartup, err\n\t}\n\n\t// load specified storage or fallback to default\n\tvar stor certmagic.Storage\n\tctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})\n\tdefer cancel()\n\tif storageCfg != nil && storageCfg.StorageRaw != nil {\n\t\tval, err := ctx.LoadModule(storageCfg, \"StorageRaw\")\n\t\tif err != nil {\n\t\t\treturn caddy.ExitCodeFailedStartup, err\n\t\t}\n\t\tstor, err = val.(caddy.StorageConverter).CertMagicStorage()","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/cmd/storagefuncs.go#L126-L162","documentation":"The periodic/background ECH key rotation (rotateECHKeys) refreshes its in-memory view of stored configs before deciding what to rotate, and setConfigsFromStorage failed during that refresh. The comment says this re-read guards against another instance having updated storage concurrently.","triggerScenarios":"rotateECHKeys acquires the ech_rotation lock, calls setConfigsFromStorage, and storage.List or a nested Load returns an error: backend outage, permissions, corrupt state.","commonSituations":"Multi-instance clusters where one node's view of shared storage goes stale or the backend has an outage during the scheduled rotation tick; storage keys manually deleted or corrupted while Caddy runs.","solutions":["Inspect the wrapped error for the storage operation that failed.","Restore storage availability; the rotation loop retries on its next tick, so often no restart is needed once the backend recovers.","Check that no external process is mutating or pruning the ech/configs storage prefix.","If corruption is indicated, reset the ech/configs folder as a last resort (ECH configs regenerate and republish)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"Log-and-retry: this occurs on the background maintenance loop; alert if it persists across ticks, but existing ECH configs keep serving.","preventionTips":["In clusters, ensure all instances point at the same storage so the re-read succeeds.","Do not externally prune ech/configs keys while instances run.","Track storage error rates with metrics/alerts."],"tags":["caddy","caddytls","ech","rotation","storage","cluster"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}