{"record":{"id":"3e8a202e24215b17","repo":"BoundaryML/baml","slug":"github-api-request-failed-with-status","errorCode":null,"errorMessage":"GitHub API request failed with status {}: {}","messagePattern":"GitHub API request failed with status (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/playground-server/src/server.rs","lineNumber":145,"sourceCode":"\n    tracing::info!(\"Sending request to GitHub API...\");\n    let resp = client\n        .get(&api_url)\n        .header(\"User-Agent\", \"baml-playground-server\")\n        .send()\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to fetch release metadata: {e}\"))?;\n\n    tracing::info!(\"Received response with status: {}\", resp.status());\n\n    // Check if the response is successful\n    if !resp.status().is_success() {\n        let status = resp.status();\n        let body = resp\n            .text()\n            .await\n            .unwrap_or_else(|_| \"Failed to read response body\".to_string());\n        return Err(anyhow::anyhow!(\n            \"GitHub API request failed with status {}: {}\",\n            status,\n            body\n        ));\n    }\n\n    tracing::info!(\"Parsing JSON response...\");\n    let release: serde_json::Value = resp\n        .json()\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to parse JSON response: {e}\"))?;\n\n    // Find the main asset\n    let assets = release[\"assets\"]\n        .as_array()\n        .ok_or_else(|| anyhow::anyhow!(\"No assets in release metadata\"))?;\n    let asset = assets\n        .iter()","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/playground-server/src/server.rs#L127-L163","documentation":"After sending the release-metadata request, get_playground_dist checks resp.status().is_success(). If GitHub answered with a non-2xx status (404 for a missing release, 403 rate limit, 5xx server error), it reads the response body and returns this error including the status and body text. The server side of the request succeeded but GitHub rejected or failed it.","triggerScenarios":"The GET to the GitHub releases API returns a non-success HTTP status — most commonly 403 rate-limit (unauthenticated GitHub API: 60 req/hour per IP), 404 for a nonexistent release/tag, or 5xx from GitHub.","commonSituations":"Shared CI IPs hitting GitHub's unauthenticated rate limit; the configured release tag/asset no longer exists after a repo reorganization or version change; GitHub incidents.","solutions":["Check the status in the message: 403 with 'rate limit' in the body means wait or set a GITHUB_TOKEN to raise the limit.","Verify the release/tag being queried still exists on the GitHub repo and that the repo/API URL is correct.","Retry later if the status is 5xx (GitHub-side incident).","Pin the server to a known-good release version instead of always fetching the latest release."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// inspect the embedded status/body to branch on cause\nmatch get_playground_dist().await {\n    Err(e) if e.to_string().contains(\"status 403\") => {\n        eprintln!(\"GitHub rate limited or forbidden; set GITHUB_TOKEN or wait\");\n    }\n    Err(e) if e.to_string().contains(\"status 404\") => {\n        eprintln!(\"Release not found; pin a valid version\");\n    }\n    Err(e) => return Err(e),\n    Ok(d) => Ok(d),\n}","preventionTips":["Set a GITHUB_TOKEN to avoid unauthenticated rate limits (60/hr per IP)","Pin the playground version instead of always fetching latest","Cache successful metadata responses","Check the status/body in the error message before retrying"],"tags":["http","github-api","http-status","rust"],"backgroundTag":"http-error-response","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}