{"record":{"id":"461af27c27574b76","repo":"virattt/ai-hedge-fund","slug":"method-path-returned-resp-status-code-resp","errorCode":null,"errorMessage":"{method} {path} returned {resp.status_code}: {resp.text[:200]}","messagePattern":"(.+?) (.+?) returned (.+?): (.+?)","errorType":"exception","errorClass":"FDClientError","httpStatus":null,"severity":"error","filePath":"hedge_fund/data/client.py","lineNumber":293,"sourceCode":"                )\n            except requests.RequestException as exc:\n                raise FDClientError(\n                    f\"{method} {path} failed: {exc}\", path=path,\n                ) from exc\n\n            if resp.status_code == 429 and delay is not None:\n                logger.info(\n                    \"Rate limited (429), retrying in %ds (attempt %d/%d)\",\n                    delay, attempt + 1, len(self._RETRY_DELAYS),\n                )\n                time.sleep(delay)\n                continue\n\n            if resp.status_code == 404:\n                return None\n\n            if resp.status_code >= 400:\n                raise FDClientError(\n                    f\"{method} {path} returned {resp.status_code}: {resp.text[:200]}\",\n                    status_code=resp.status_code, path=path,\n                )\n\n            return resp\n\n        raise FDClientError(\n            f\"{method} {path} rate limited (429) after {len(self._RETRY_DELAYS)} retries\",\n            status_code=429, path=path,\n        )\n","sourceCodeStart":275,"sourceCodeEnd":304,"githubUrl":"https://github.com/virattt/ai-hedge-fund/blob/eff8a7320fcf0b473b135690fa1a5b0d9b022a83/hedge_fund/data/client.py#L275-L304","documentation":"Raised by FDClient._request (hedge_fund/data/client.py:293) when the provider returns any HTTP >= 400 status other than 429 (rate-limited, retried separately) and 404 (mapped to None = 'no data'). The message embeds the status code and the first 200 chars of the response body. Like all FDClientErrors it is an infrastructure failure: auth problems, bad requests, and server errors all land here.","triggerScenarios":"HTTP 401/403 from an invalid or expired API key; 400 from a malformed query (bad ticker format, invalid date params); 5xx when the provider is down. Concretely: FDClient().get_prices('INVALID%%TICKER', ...) producing a 400, or an unset FMP/API key producing 401 on the first call of a backtest.","commonSituations":"Expired or forgotten API key in .env; the provider changed its query parameter schema (client library out of date vs API version); free-tier plan limits returning 402/403; scheduled provider maintenance returning 503.","solutions":["Read the status_code attribute on FDClientError: 401/403 means fix the API key in .env; 400 means the request params (ticker/date format) are wrong; 5xx means wait and retry.","Verify the API key is present and valid with a one-line probe: FDClient().get_prices('SPY', <recent week>) and inspect the error.","If the body text mentions plan/subscription limits, upgrade the plan or reduce the number of symbols/periods requested.","For 5xx, retry with backoff later — the provider is unhealthy, nothing in your code is wrong."],"exampleFix":"# before\ntry:\n    metrics = client.get_financial_metrics(ticker, as_of, period=\"ttm\", limit=20)\nexcept FDClientError as e:\n    raise  # opaque crash\n\n# after\ntry:\n    metrics = client.get_financial_metrics(ticker, as_of, period=\"ttm\", limit=20)\nexcept FDClientError as e:\n    if e.status_code in (401, 403):\n        raise RuntimeError(\"API key rejected — check .env\") from e\n    raise","handlingStrategy":"try-catch","validationCode":"def verify_api_key(client) -> bool:\n    \"\"\"One cheap request; 401/403 here beats a crash 40 minutes into a run.\"\"\"\n    try:\n        client.get_prices(\"SPY\", \"2024-01-02\", \"2024-01-05\")\n        return True\n    except Exception:\n        return False","typeGuard":"from hedge_fund.data.client import FDClientError\n\ndef is_auth_error(e: FDClientError) -> bool:\n    return isinstance(e, FDClientError) and e.status_code in (401, 403)\n\ndef is_server_error(e: FDClientError) -> bool:\n    return isinstance(e, FDClientError) and e.status_code is not None and e.status_code >= 500","tryCatchPattern":"from hedge_fund.data.client import FDClientError\n\ntry:\n    data = client.get_prices(ticker, start, end)\nexcept FDClientError as e:\n    if e.status_code in (401, 403):\n        raise SystemExit(\"API key rejected — check the key in .env\") from e\n    if e.status_code == 400:\n        raise ValueError(f\"bad request params for {ticker}: {e}\") from e\n    if e.status_code is not None and e.status_code >= 500:\n        logger.warning(\"provider 5xx, will retry later: %s\", e)\n        raise\n    raise","preventionTips":["Probe the key with one tiny request at startup of any long run.","Branch on e.status_code rather than parsing the message text.","Treat 4xx (except 429) as your-side bugs and 5xx as wait-and-retry."],"tags":["http","api-key","data-client","status-code"],"backgroundTag":null,"analyzedSha":"eff8a7320fcf0b473b135690fa1a5b0d9b022a83","analyzedAt":"2026-08-15T00:22:46.567Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}