{"record":{"id":"bb7f5d888c35379d","repo":"headroomlabs-ai/headroom","slug":"upstream-request-failed-0","errorCode":null,"errorMessage":"upstream request failed: {0}","messagePattern":"upstream request failed: (.+?)","errorType":"http","errorClass":"ProxyError::Upstream","httpStatus":502,"severity":"error","filePath":"crates/headroom-proxy/src/error.rs","lineNumber":9,"sourceCode":"//! Error types for the proxy.\n\nuse axum::http::StatusCode;\nuse axum::response::{IntoResponse, Response};\nuse thiserror::Error;\n\n#[derive(Debug, Error)]\npub enum ProxyError {\n    #[error(\"upstream request failed: {0}\")]\n    Upstream(#[from] reqwest::Error),\n\n    #[error(\"invalid upstream URL: {0}\")]\n    InvalidUpstream(String),\n\n    #[error(\"invalid header: {0}\")]\n    InvalidHeader(String),\n\n    #[error(\"websocket error: {0}\")]\n    WebSocket(String),\n\n    #[error(\"io error: {0}\")]\n    Io(#[from] std::io::Error),\n\n    /// PR-A8 / P5-59: request body exceeded the configured cap. RFC 7231\n    /// §6.5.11: 413 Payload Too Large. Previously surfaced as\n    /// `InvalidHeader` (400) which mis-classified an oversize body as a\n    /// header parse error; clients with retry-on-413 logic broke.","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/crates/headroom-proxy/src/error.rs#L1-L27","documentation":"Generic reqwest failure while performing the upstream HTTP request. IntoResponse specializes it: is_timeout() maps to 504 Gateway Timeout, is_connect() maps to 502 Bad Gateway, everything else is 502 with the raw error text. It is the proxy's workhorse network error.","triggerScenarios":"Any reqwest::Error bubbled via #[from]: connection refused/reset to the upstream LLM endpoint, DNS resolution failure, TLS handshake error, request timeout exceeding the configured client timeout, body read interrupted mid-response.","commonSituations":"Upstream provider outage or throttling that manifests as resets; wrong upstream URL/port in config; egress blocked by firewall/proxy; client timeout set lower than slow LLM generation latency, causing spurious 504s on long completions.","solutions":["Classify first: the HTTP status the client sees (504 vs 502) already tells you timeout vs connect/other — check which you got.","For 504: raise the proxy's upstream request timeout above worst-case generation time, or make streaming requests so the connection stays hot.","For 502 on connect: verify upstream host/port/DNS and network egress from the proxy host (curl the same endpoint).","Enable retries with backoff for idempotent calls; check the upstream provider's status page."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.execute(req).await {\n    Err(e) if e.is_timeout() => retry_with_backoff().await,        // 504 path\n    Err(e) if e.is_connect() => fail_fast(BadGateway, e),           // 502 path\n    Err(e) => fail_fast(BadGateway, e),\n    Ok(resp) => handle(resp).await,\n}","preventionTips":["Set upstream timeout above worst-case generation latency, or stream responses.","Health-check the upstream endpoint at startup to catch config/egress issues early.","Make clients honor 502/504 with exponential backoff plus jitter."],"tags":["network","upstream","http","timeout","rust"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}