{"record":{"id":"fa04df6c7b29e43c","repo":"Kuberwastaken/claurst","slug":"growthbook-api-returned-status","errorCode":null,"errorMessage":"GrowthBook API returned status {}: {}","messagePattern":"GrowthBook API returned status (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-rust/crates/core/src/feature_flags.rs","lineNumber":154,"sourceCode":"    async fn fetch_from_api(&self) -> Result<CachedFlags> {\r\n        let api_key = std::env::var(\"GROWTHBOOK_API_KEY\").ok();\r\n\r\n        let mut builder = self.http_client.get(&self.api_endpoint);\r\n\r\n        // Add authorization header if API key is available\r\n        if let Some(key) = api_key {\r\n            builder = builder.header(\"Authorization\", format!(\"Bearer {}\", key));\r\n        }\r\n\r\n        let response = builder\r\n            .timeout(Duration::from_secs(10))\r\n            .send()\r\n            .await\r\n            .context(\"Failed to fetch from GrowthBook API\")?;\r\n\r\n        let status = response.status();\r\n        if !status.is_success() {\r\n            return Err(anyhow!(\r\n                \"GrowthBook API returned status {}: {}\",\r\n                status.as_u16(),\r\n                response.text().await.unwrap_or_default()\r\n            ));\r\n        }\r\n\r\n        let body = response\r\n            .json::<GrowthBookApiResponse>()\r\n            .await\r\n            .context(\"Failed to parse GrowthBook API response\")?;\r\n\r\n        Ok(CachedFlags {\r\n            flags: body\r\n                .features\r\n                .into_iter()\r\n                .map(|f| (f.key.clone(), f))\r\n                .collect(),\r\n            fetched_at: SystemTime::now()\r","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/core/src/feature_flags.rs#L136-L172","documentation":"Thrown by `fetch_from_api` (invoked by `fetch_flags_async`) when the GrowthBook HTTP API responds with a non-success status code. The message embeds the numeric status and, when available, the response body text, so the caller can see the server-side reason the flag fetch failed.","triggerScenarios":"The reqwest request to the GrowthBook API completes but `status.is_success()` is false — 401/403 for bad or expired API credentials, 404 for a wrong API URL, 429 rate limiting, or 5xx server errors.","commonSituations":"Rotated or revoked GrowthBook API token; misconfigured GrowthBook API hostname; rate limiting after polling too frequently; GrowthBook service outage returning 502/503.","solutions":["Check the embedded status/body: 401/403 means fix the API token/credentials.","Verify the GrowthBook API URL configuration points at the correct environment.","If 429, back off and retry with exponential delay / reduce polling frequency.","For 5xx, retry later or fall back to cached/last-known flag values.","Run with the error body from the message to confirm the server-side reason."],"exampleFix":"// resilient flag fetch with fallback\nlet flags = match fetch_flags_async().await {\n    Ok(f) => f,\n    Err(e) if e.to_string().contains(\"status 429\") => {\n        tokio::time::sleep(Duration::from_secs(30)).await;\n        fetch_flags_async().await.unwrap_or_else(|_| cached_flags())\n    }\n    Err(_) => cached_flags(), // fall back to last known flags\n};","handlingStrategy":"retry","validationCode":"// preflight: verify credentials/URL with a lightweight request\nlet status = client.get(&api_url).send().await?.status();\nif !status.is_success() { /* fix token or URL before fetching flags */ }","typeGuard":"fn is_retryable_status(u: u16) -> bool { u == 429 || u >= 500 }","tryCatchPattern":"match fetch_flags_async().await {\n    Ok(f) => f,\n    Err(e) if e.to_string().contains(\"status 429\") || e.to_string().contains(\"status 5\") => {\n        backoff_retry(MAX_RETRIES).await\n    }\n    Err(e) => fall_back_to_cached_flags(e),\n}","preventionTips":["Keep the GrowthBook API token valid and rotated before expiry.","Verify the API URL environment setting (prod vs staging).","Cache last-known-good flags and fall back when the API errors.","Add exponential backoff for 429/5xx instead of tight polling."],"tags":["http","api","feature-flags","growthbook","network"],"backgroundTag":"http-error-response","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}