{"record":{"id":"65807af788631e36","repo":"caddyserver/caddy","slug":"failed-getting-eab-credentials-http-d-s-code","errorCode":null,"errorMessage":"failed getting EAB credentials: HTTP %d: %s (code %d)","messagePattern":"failed getting EAB credentials: HTTP (.+?): (.+?) \\(code (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/acmeissuer.go","lineNumber":406,"sourceCode":"\t}\n\tdefer resp.Body.Close()\n\n\tvar result struct {\n\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//","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/acmeissuer.go#L388-L424","documentation":"ZeroSSL's EAB API responded with a structured error: the decoded JSON contains a non-zero error.code, and Caddy reports the HTTP status, error type, and API error code. Notably ZeroSSL returns HTTP 200 even on errors, so this code field is checked before the status code. Typical codes include invalid email (202) or hitting API limits.","triggerScenarios":"POSTing an invalid/malformed email to /acme/eab-credentials-email; ZeroSSL rejecting the account creation (e.g. blocked email domain); API rate limiting; ZeroSSL API reporting 'Email does not look right' style errors.","commonSituations":"Typo'd or syntactically invalid email in the global email option; disposable/placeholder emails like test@test.com being rejected; repeated issuance attempts from the same IP hitting ZeroSSL's limits.","solutions":["Verify the configured email is a real, correctly formatted mailbox you control (it receives ZeroSSL notifications).","Match the error code against ZeroSSL's API documentation (e.g. code 202 = invalid email) and correct the input.","If rate limited, wait before retrying or use manual EAB credentials generated in the ZeroSSL dashboard under Developer settings.","Ensure only one Caddy instance/key per policy is requesting EAB to avoid limit exhaustion."],"exampleFix":"# before\n{\n\temail not-an-email\n}\n\n# after\n{\n\temail admin@example.com\n}","handlingStrategy":"validation","validationCode":"// RFC-ish email sanity check before relying on ZeroSSL auto-EAB.\nfunc validEmail(s string) bool {\n    at := strings.IndexByte(s, '@')\n    return at > 0 && at < len(s)-1 && !strings.ContainsAny(s, \" \\\\t\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a real mailbox for the email option; avoid test@example-style addresses.","Cross-reference the reported ZeroSSL error code in the message with their API docs.","Keep manual EAB credentials as a fallback for rejected emails."],"tags":["tls","acme","zerossl","api-error","configuration"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}