{"record":{"id":"f1ab6e291c6a16c5","repo":"TauricResearch/TradingAgents","slug":"fred-request-failed-message","errorCode":null,"errorMessage":"FRED request failed: {message}","messagePattern":"FRED request failed: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tradingagents/dataflows/fred.py","lineNumber":131,"sourceCode":"            f\"FRED series ID (e.g. 'CPIAUCSL').\"\n        )\n    return candidate\n\n\ndef _request(path: str, params: dict) -> dict:\n    \"\"\"GET a FRED endpoint, surfacing FRED's JSON error body on a bad request.\"\"\"\n    api_params = {**params, \"api_key\": get_api_key(), \"file_type\": \"json\"}\n    response = requests.get(\n        f\"{FRED_API_BASE}/{path}\", params=api_params, timeout=REQUEST_TIMEOUT\n    )\n    # FRED returns 400 with a JSON {\"error_message\": ...} for unknown series IDs\n    # or malformed params; turn that into a clear, actionable error.\n    if response.status_code == 400:\n        try:\n            message = response.json().get(\"error_message\", response.text)\n        except ValueError:\n            message = response.text\n        raise ValueError(f\"FRED request failed: {message}\")\n    response.raise_for_status()\n    return response.json()\n\n\ndef get_macro_data(\n    indicator: str,\n    curr_date: str,\n    look_back_days: int | None = None,\n) -> str:\n    \"\"\"Fetch a FRED macroeconomic series as a formatted markdown report.\n\n    Args:\n        indicator: A friendly alias (e.g. \"cpi\", \"unemployment\", \"10y_treasury\")\n            or a raw FRED series ID (e.g. \"CPIAUCSL\", \"DGS10\").\n        curr_date: End of the window (yyyy-mm-dd); no later observations are\n            returned, so a past date never leaks future data.\n        look_back_days: Trailing window length; ``None`` uses DEFAULT_LOOKBACK_DAYS.\n","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/TauricResearch/TradingAgents/blob/a33fd4c0f134485a43553a2c23a63cb14adbd88f/tradingagents/dataflows/fred.py#L113-L149","documentation":"Raised by _request() in tradingagents/dataflows/fred.py when the FRED API answers HTTP 400 with a JSON body; the JSON's error_message (or raw text if the body isn't JSON) is embedded so the failure is actionable. It is a plain ValueError, so the router's generic handler records it as the first_error and it propagates only if no other configured vendor succeeds.","triggerScenarios":"Requesting a series ID that does not exist (e.g. 'CPIAUCSL' typo'd as 'CPIAUCS'), malformed parameters, or an invalid API key value that FRED rejects at the parameter level. Note: a *missing* key raises FredNotConfiguredError earlier; a syntactically bad request gets this 400 error.","commonSituations":"LLM-constructed or user-supplied series IDs that look valid but aren't; stale series IDs discontinued by FRED; passing wrong parameter names for observation endpoints; keys with whitespace causing auth failure at FRED's edge.","solutions":["Read the embedded message — FRED states the exact problem (e.g. 'The series does not exist')","Validate the series ID first via FRED's search: curl 'https://api.stlouisfed.org/fred/series/search?search_text=...&api_key=...&file_type=json'","Prefer documented aliases (MACRO_SERIES) over hand-typed IDs","Wrap the call in try/except ValueError to degrade gracefully (report unavailable macro data) rather than aborting the run"],"exampleFix":"# before\nget_macro_data(\"NOT_A_SERIES\", \"2025-06-10\")\n# -> ValueError: FRED request failed: The series 'NOT_A_SERIES' does not exist...\n\n# after\ntry:\n    report = get_macro_data(\"CPIAUCSL\", \"2025-06-10\")\nexcept ValueError as e:\n    report = f\"Macro data unavailable: {e}\"  # degrade instead of crash","handlingStrategy":"try-catch","validationCode":"import requests, os\n\ndef fred_series_exists(series_id: str) -> bool:\n    r = requests.get(\"https://api.stlouisfed.org/fred/series\", params={\n        \"series_id\": series_id, \"api_key\": os.environ[\"FRED_API_KEY\"], \"file_type\": \"json\"}, timeout=15)\n    return r.ok and r.json().get(\"seriess\")","typeGuard":null,"tryCatchPattern":"try:\n    report = get_macro_data(series, curr_date)\nexcept ValueError as e:\n    if str(e).startswith(\"FRED request failed:\"):\n        report = f\"Macro series {series} unavailable ({e})\"  # log & degrade; do not blindly retry a 400\n    else:\n        raise","preventionTips":["Treat a 400 as permanent: fix the series ID, don't retry the same request","Validate series IDs via FRED's search endpoint when accepting free-form input","Prefer built-in aliases over hand-typed IDs"],"tags":["fred","http-400","macro-data","api-error"],"backgroundTag":null,"analyzedSha":"a33fd4c0f134485a43553a2c23a63cb14adbd88f","analyzedAt":"2026-08-14T19:45:16.920Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}