{"record":{"id":"b5694a8b79f32d79","repo":"caddyserver/caddy","slug":"failed-getting-eab-credentials-http-d","errorCode":null,"errorMessage":"failed getting EAB credentials: HTTP %d","messagePattern":"failed getting EAB credentials: HTTP (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/acmeissuer.go","lineNumber":410,"sourceCode":"\t\tSuccess bool `json:\"success\"`\n\t\tError   struct {\n\t\t\tCode int    `json:\"code\"`\n\t\t\tType string `json:\"type\"`\n\t\t} `json:\"error\"`\n\t\tEABKID     string `json:\"eab_kid\"`\n\t\tEABHMACKey string `json:\"eab_hmac_key\"`\n\t}\n\terr = json.NewDecoder(resp.Body).Decode(&result)\n\tif err != nil {\n\t\treturn nil, acct, fmt.Errorf(\"decoding API response: %v\", err)\n\t}\n\tif result.Error.Code != 0 {\n\t\t// do this check first because ZeroSSL's API returns 200 on errors\n\t\treturn nil, acct, fmt.Errorf(\"failed getting EAB credentials: HTTP %d: %s (code %d)\",\n\t\t\tresp.StatusCode, result.Error.Type, result.Error.Code)\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, acct, fmt.Errorf(\"failed getting EAB credentials: HTTP %d\", resp.StatusCode)\n\t}\n\n\tif c := iss.logger.Check(zapcore.InfoLevel, \"generated EAB credentials\"); c != nil {\n\t\tc.Write(zap.String(\"key_id\", result.EABKID))\n\t}\n\n\treturn &acme.EAB{\n\t\tKeyID:  result.EABKID,\n\t\tMACKey: result.EABHMACKey,\n\t}, acct, nil\n}\n\n// UnmarshalCaddyfile deserializes Caddyfile tokens into iss.\n//\n//\t... acme [<directory_url>] {\n//\t    dir <directory_url>\n//\t    test_dir <test_directory_url>\n//\t    email <email>","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/acmeissuer.go#L392-L428","documentation":"The EAB credentials request completed and the body decoded without a structured error code, but the HTTP status was not 200 (e.g. 429, 500, 503). This branch is reached only after the ZeroSSL-specific error.code check passed, so it represents non-200 statuses with otherwise clean payloads — generally server-side or rate-limit conditions.","triggerScenarios":"ZeroSSL returning 429 (rate limit) or 5xx during API incidents; gateway timeouts from ZeroSSL's infrastructure; any non-200 response whose JSON has error.code == 0.","commonSituations":"Bursty certificate issuance (many new domains at once) tripping ZeroSSL rate limits; ZeroSSL outages; retry storms after config reloads.","solutions":["Wait and retry: reload Caddy or trigger re-issuance after a few minutes; 429/5xx are usually transient.","Reduce issuance burstiness by staggering new hostnames or pre-generating EAB credentials.","Check ZeroSSL status/announcements for ongoing incidents.","As a durable fallback, configure manual external_account credentials or use Let's Encrypt as the issuer."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := registerZeroSSL(ctx); err != nil {\n    msg := err.Error()\n    if strings.Contains(msg, \"failed getting EAB credentials: HTTP 4\") || strings.Contains(msg, \"HTTP 5\") {\n        // rate limit / server error: back off and retry later\n        scheduleRetry(15 * time.Minute)\n    }\n}","preventionTips":["Stagger new-domain issuance to avoid EAB rate limits.","Avoid config reload loops that re-trigger registration.","Subscribe to ZeroSSL status notifications for incident windows."],"tags":["tls","acme","zerossl","rate-limit","transient"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}