{"record":{"id":"e1417dbbeb1d6d75","repo":"bitwarden/server","slug":"request-failed-status-code-0","errorCode":null,"errorMessage":"Request failed. Status code: {0}","messagePattern":"Request failed\\. Status code: (.+?)","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/Dirt/Controllers/HibpController.cs","lineNumber":90,"sourceCode":"            return Content(\"[]\", \"application/json\");\n        }\n        else if (response.StatusCode == HttpStatusCode.TooManyRequests && retry)\n        {\n            var delay = 2000;\n            if (response.Headers.Contains(\"retry-after\"))\n            {\n                var vals = response.Headers.GetValues(\"retry-after\");\n                if (vals.Any() && int.TryParse(vals.FirstOrDefault(), out var secDelay))\n                {\n                    delay = (secDelay * 1000) + 200;\n                }\n            }\n            await Task.Delay(delay);\n            return await SendAsync(username, false);\n        }\n        else\n        {\n            throw new BadRequestException(\"Request failed. Status code: \" + response.StatusCode);\n        }\n    }\n\n    private string GetClientId()\n    {\n        var userId = _userService.GetProperUserId(User).Value;\n        using (var sha256 = SHA256.Create())\n        {\n            var hash = sha256.ComputeHash(userId.ToByteArray());\n            return Convert.ToBase64String(hash);\n        }\n    }\n}\n","sourceCodeStart":72,"sourceCodeEnd":104,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Dirt/Controllers/HibpController.cs#L72-L104","documentation":"Thrown by the HIBP (HaveIBeenPwned) breach-lookup proxy when the upstream HIBP API returns a status code that is neither 200 (success), 404 (no breaches — mapped to an empty array), nor a retryable 429. The HIBP API key must be configured (_globalSettings.HibpApiKey); any other failure (auth, server error, or a second 429 after the single automatic retry) is wrapped into a 400 BadRequest that includes the upstream status code.","triggerScenarios":"GET /hibp/breach?username=<user> when the HIBP v3 API responds 401 (bad/expired API key), 403 (key valid but blocked / wrong scope), 5xx (HIBP outage), or a second consecutive 429 after the built-in single retry has already run (retry=false on the recursive call).","commonSituations":"Self-hosted deployment where GlobalSettings:HibpApiKey is missing, expired, or revoked; HIBP rate limit exceeded beyond the one automatic retry (the key's per-minute quota is exhausted); transient HIBP 5xx during their incidents; network egress blocked so the HttpClient gets a non-success or the request itself faults upstream.","solutions":["Verify GlobalSettings:HibpApiKey is set to a valid, active HIBP API key (sign in at haveibeenpwned.com/api/key) and restart the server.","Inspect the embedded status code in the 400 response body: 401/403 → fix the key; 429 → wait and reduce call frequency or upgrade the HIBP subscription tier; 5xx → HIBP is down, retry later.","If self-hosted behind a proxy, confirm egress to https://haveibeenpwned.com/api/v3/ is allowed and not being throttled by an intermediary.","For chronic 429s, add client-side caching/debouncing of breach lookups so repeated username checks don't each hit HIBP."],"exampleFix":"// before: a single retry, then a hard 400 on the next non-success\n// after (extend retry budget + distinguish auth errors):\nelse if (response.StatusCode == HttpStatusCode.Unauthorized ||\n         response.StatusCode == HttpStatusCode.Forbidden)\n{\n    throw new BadRequestException(\"HIBP API key is invalid or unauthorized.\");\n}\nelse\n{\n    throw new BadRequestException(\"Request failed. Status code: \" + response.StatusCode);\n}","handlingStrategy":"retry","validationCode":"// Before calling /hibp/breach, ensure the deployment has a key configured.\n// (Server-side config check; client can't see it, so just be ready to retry/back off.)\nif (string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(\"GlobalSettings__HibpApiKey\")))\n    throw new InvalidOperationException(\"HIBP API key is not configured on the server.\");","typeGuard":null,"tryCatchPattern":"// Client calling GET /hibp/breach\ntry { var breaches = await client.GetAsync($\"/hibp/breach?username={username}\"); }\ncatch (HttpRequestException ex) when (ex.Message.Contains(\"Status code\"))\n{\n    // Parse embedded status; 401/403 → key issue (alert ops), 429/5xx → back off and retry\n    if (ex.Message.Contains(\"429\") || ex.Message.Contains(\"50\")) await Task.Delay(backoff);\n    else throw;\n}","preventionTips":["Keep the HIBP API key valid and monitored; alert on 401/403 in the response body.","Cache breach results client-side to reduce call frequency and avoid 429s.","Treat 5xx from HIBP as transient — retry with exponential backoff."],"tags":["network","external-api","hibp","configuration","csharp","aspnetcore"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}