{"record":{"id":"3ca30367b0398ef4","repo":"caddyserver/caddy","slug":"protocol-argument-was-not-a-string","errorCode":null,"errorMessage":"protocol argument was not a string","messagePattern":"protocol argument was not a string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/matchers.go","lineNumber":1423,"sourceCode":"\t}\n\treturn nil\n}\n\n// CELLibrary produces options that expose this matcher for use in CEL\n// expression matchers.\n//\n// Example:\n//\n//\texpression protocol('https')\nfunc (MatchProtocol) CELLibrary(_ caddy.Context) (cel.Library, error) {\n\treturn CELMatcherImpl(\n\t\t\"protocol\",\n\t\t\"protocol_request_string\",\n\t\t[]*cel.Type{cel.StringType},\n\t\tfunc(data ref.Val) (RequestMatcherWithError, error) {\n\t\t\tprotocolStr, ok := data.(types.String)\n\t\t\tif !ok {\n\t\t\t\treturn nil, errors.New(\"protocol argument was not a string\")\n\t\t\t}\n\t\t\treturn MatchProtocol(strings.ToLower(string(protocolStr))), nil\n\t\t},\n\t)\n}\n\n// CaddyModule returns the Caddy module information.\nfunc (MatchTLS) CaddyModule() caddy.ModuleInfo {\n\treturn caddy.ModuleInfo{\n\t\tID:  \"http.matchers.tls\",\n\t\tNew: func() caddy.Module { return new(MatchTLS) },\n\t}\n}\n\n// Match returns true if r matches m.\nfunc (m MatchTLS) Match(r *http.Request) bool {\n\tmatch, _ := m.MatchWithError(r)\n\treturn match","sourceCodeStart":1405,"sourceCodeEnd":1441,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/matchers.go#L1405-L1441","documentation":"loadECHConfig could not load an ECH private key (key.bin under ech/configs/<id>) from storage, AND the compensating cleanup (deleting the config folder to free the config ID) also failed. Caddy tolerates a missing/corrupt key by deleting the folder, so this error means storage is doubly broken: load fails and delete fails.","triggerScenarios":"storage.Load of key.bin errors AND storage.Delete of the cfgIDKey folder errors: read-only storage (load permission denied, delete not permitted), backend outage affecting both operations, or the folder key exists but the child key is missing on a backend where Load errors on missing keys.","commonSituations":"Data directory made read-only (disk error, Docker read-only mount, SELinux); partial storage states where key.bin was deleted but the folder remains; remote storage outages.","solutions":["Check both wrapped errors: the load error explains why recovery was attempted; the delete error explains why it failed.","Restore read/write access to the storage backend or data directory.","Manually remove the ech/configs/<id> folder named in the error once storage is healthy, then restart so the config ID is freed and regenerated.","Prevent manual deletion of individual files (key.bin) inside config folders — delete whole folders only."],"exampleFix":"# before: partially-deleted config leaves stray folder\nrm /var/lib/caddy/ech/configs/42/key.bin  # breaks load\n# after: remove the whole config folder\nrm -rf /var/lib/caddy/ech/configs/42","handlingStrategy":"validation","validationCode":"// Pre-flight: confirm the storage tree is readable AND deletable before ECH use:\nif _, err := storage.Load(ctx, path.Join(\"ech/configs\", id, \"key.bin\")); err != nil {\n    if err := storage.Delete(ctx, path.Join(\"ech/configs\", id)); err != nil {\n        return fmt.Errorf(\"storage cannot recover from corrupt config: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err != nil { if delErr != nil { // storage doubly broken: halt, require operator intervention on the named cfgIDKey } } — the error message includes the exact storage key to clean up.","preventionTips":["Never make the data directory read-only while ECH is enabled.","Delete whole config folders, never individual key.bin files.","Verify delete permissions when hardening/SELinux policies are applied."],"tags":["caddy","caddytls","ech","storage","cleanup","read-only"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}