virattt/ai-hedge-fund · error · FDClientError
{method} {path} returned {resp.status_code}: {resp.text[:200
Error message
{method} {path} returned {resp.status_code}: {resp.text[:200]} What it means
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.
Source
Thrown at hedge_fund/data/client.py:293
)
except requests.RequestException as exc:
raise FDClientError(
f"{method} {path} failed: {exc}", path=path,
) from exc
if resp.status_code == 429 and delay is not None:
logger.info(
"Rate limited (429), retrying in %ds (attempt %d/%d)",
delay, attempt + 1, len(self._RETRY_DELAYS),
)
time.sleep(delay)
continue
if resp.status_code == 404:
return None
if resp.status_code >= 400:
raise FDClientError(
f"{method} {path} returned {resp.status_code}: {resp.text[:200]}",
status_code=resp.status_code, path=path,
)
return resp
raise FDClientError(
f"{method} {path} rate limited (429) after {len(self._RETRY_DELAYS)} retries",
status_code=429, path=path,
)
View on GitHub (pinned to eff8a7320f)
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.
Example fix
# before
try:
metrics = client.get_financial_metrics(ticker, as_of, period="ttm", limit=20)
except FDClientError as e:
raise # opaque crash
# after
try:
metrics = client.get_financial_metrics(ticker, as_of, period="ttm", limit=20)
except FDClientError as e:
if e.status_code in (401, 403):
raise RuntimeError("API key rejected — check .env") from e
raise Defensive patterns
Strategy: try-catch
Validate before calling
def verify_api_key(client) -> bool:
"""One cheap request; 401/403 here beats a crash 40 minutes into a run."""
try:
client.get_prices("SPY", "2024-01-02", "2024-01-05")
return True
except Exception:
return False Type guard
from hedge_fund.data.client import FDClientError
def is_auth_error(e: FDClientError) -> bool:
return isinstance(e, FDClientError) and e.status_code in (401, 403)
def is_server_error(e: FDClientError) -> bool:
return isinstance(e, FDClientError) and e.status_code is not None and e.status_code >= 500 Try / catch
from hedge_fund.data.client import FDClientError
try:
data = client.get_prices(ticker, start, end)
except FDClientError as e:
if e.status_code in (401, 403):
raise SystemExit("API key rejected — check the key in .env") from e
if e.status_code == 400:
raise ValueError(f"bad request params for {ticker}: {e}") from e
if e.status_code is not None and e.status_code >= 500:
logger.warning("provider 5xx, will retry later: %s", e)
raise
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- {method} {path} failed: {exc}
- {method} {path} rate limited (429) after {len(self._RETRY_DE
- {env_var} not found. Set it in your .env to use {provider} m
AI-assisted analysis of virattt/ai-hedge-fund@eff8a7320f (2026-08-15).
Data as JSON: /api/errors/461af27c27574b76.
Report an issue: GitHub.