fix(alpha_vantage): keep the API key out of every error an Alpha Vantage answer raises

- rate-limit and invalid-key notices are scrubbed of the key as the rejection message is
This commit is contained in:
Yijia-Xiao
2026-10-03 21:27:43 +00:00
parent b838e257ee
commit 97b79e08c3
2 changed files with 23 additions and 3 deletions
+17
View File
@@ -86,6 +86,23 @@ def test_a_rejected_request_is_unavailable_not_data(monkeypatch):
assert out.startswith("DATA_UNAVAILABLE"), out
@pytest.mark.unit
@pytest.mark.parametrize("body", [
'{"Note": "Thank you for using key k-secret. API call frequency is 5 calls per minute."}',
'{"Information": "the apikey k-secret is invalid or missing."}',
])
def test_the_key_never_reaches_an_error_message(monkeypatch, body):
"""Alpha Vantage can echo the key in its notices; error text reaches logs and reports."""
from tradingagents.dataflows.errors import VendorError
monkeypatch.setenv("ALPHA_VANTAGE_API_KEY", "k-secret")
monkeypatch.setattr(net.requests, "get", _patched_get(body))
with pytest.raises(VendorError) as raised:
av._make_api_request("TIME_SERIES_DAILY", {"symbol": "AAPL"})
assert "k-secret" not in str(raised.value)
_FUNDAMENTALS_JSON = json.dumps({
"symbol": "AAPL",
"annualReports": [
+6 -3
View File
@@ -109,8 +109,13 @@ def _make_api_request(function_name: str, params: dict) -> dict | str:
# genuine rate limit and an invalid/missing key aren't conflated (#991):
# rate-limit phrasing is checked first because those notices also mention
# "API key" ("your API key ... 25 requests per day").
def scrubbed(text: str) -> str:
# Alpha Vantage can echo the key in its notices; error text reaches logs.
return text.replace(api_key, "***") if api_key else text
notice = response_json.get("Information") or response_json.get("Note")
if notice:
notice = scrubbed(notice)
low = notice.lower()
if any(m in low for m in ("rate limit", "requests per day", "call frequency", "premium")):
raise AlphaVantageRateLimitError(f"Alpha Vantage rate limit exceeded: {notice}")
@@ -124,9 +129,7 @@ def _make_api_request(function_name: str, params: dict) -> dict | str:
# instrument (#1442).
rejection = response_json.get("Error Message")
if rejection:
if api_key:
rejection = rejection.replace(api_key, "***")
raise VendorUnavailableError(f"Alpha Vantage rejected the request: {rejection}")
raise VendorUnavailableError(f"Alpha Vantage rejected the request: {scrubbed(rejection)}")
return response_text