fix(client): check HTTP status before parsing ping response in _validate_api_key (#5639)

This commit is contained in:
Yash Singh
2026-06-19 12:19:13 +05:30
committed by GitHub
parent bd7ce2c13c
commit ffa334537a
2 changed files with 60 additions and 4 deletions
+4 -4
View File
@@ -151,10 +151,10 @@ class MemoryClient:
try:
params = self._prepare_params()
response = self.client.get("/v1/ping/", params=params)
data = response.json()
response.raise_for_status()
data = response.json()
if data.get("org_id") and data.get("project_id"):
self.org_id = data.get("org_id")
self.project_id = data.get("project_id")
@@ -1044,10 +1044,10 @@ class AsyncMemoryClient:
},
params=params,
)
data = response.json()
response.raise_for_status()
data = response.json()
if data.get("org_id") and data.get("project_id"):
self.org_id = data.get("org_id")
self.project_id = data.get("project_id")
+56
View File
@@ -1,8 +1,11 @@
"""Tests for MemoryClient entity parameter rejection."""
import json
from unittest.mock import MagicMock, patch
import httpx
import pytest
import requests
@pytest.fixture
@@ -207,3 +210,56 @@ class TestDeleteLinked:
call_args = mock_memory_client.client.delete.call_args
assert "delete_linked" not in call_args.kwargs.get("params", {})
class TestValidateApiKeyHttpError:
"""_validate_api_key should surface a clear ValueError on a non-JSON HTTP error.
A 5xx from a CDN/proxy often has an HTML body, so response.json() fails. The
HTTP status must be checked before json() so the intended ValueError is raised
instead of a confusing JSONDecodeError during client construction.
"""
def test_sync_client_non_json_5xx_raises_clear_error(self):
# HTML body from a CDN/proxy: json() fails, but raise_for_status() reports the 503.
request = httpx.Request("GET", "https://api.mem0.ai/v1/ping/")
error_response = httpx.Response(503, text="<html>503 Service Unavailable</html>", request=request)
response = MagicMock()
response.json.side_effect = json.JSONDecodeError("Expecting value", "<html>", 0)
response.raise_for_status.side_effect = httpx.HTTPStatusError(
"Server error", request=request, response=error_response
)
with patch("mem0.client.main.httpx.Client") as mock_httpx:
mock_http_client = MagicMock()
mock_http_client.get.return_value = response
mock_httpx.return_value = mock_http_client
with patch("mem0.client.main.capture_client_event"):
from mem0.client.main import MemoryClient
with pytest.raises(ValueError) as exc_info:
MemoryClient(api_key="test-api-key")
# The HTTP status must surface as the intended "Error: ..." ValueError,
# not the raw JSONDecodeError from parsing the HTML body.
assert not isinstance(exc_info.value, json.JSONDecodeError)
assert "Error:" in str(exc_info.value)
def test_async_client_non_json_5xx_raises_clear_error(self):
request = httpx.Request("GET", "https://api.mem0.ai/v1/ping/")
error_response = httpx.Response(503, text="<html>503 Service Unavailable</html>", request=request)
response = MagicMock()
response.json.side_effect = requests.exceptions.JSONDecodeError("Expecting value", "<html>", 0)
http_error = requests.exceptions.HTTPError("Server error", response=error_response)
response.raise_for_status.side_effect = http_error
with patch("mem0.client.main.requests.get", return_value=response):
with patch("mem0.client.main.capture_client_event"):
from mem0.client.main import AsyncMemoryClient
with pytest.raises(ValueError) as exc_info:
AsyncMemoryClient(api_key="test-api-key")
assert not isinstance(exc_info.value, requests.exceptions.JSONDecodeError)
assert "Error:" in str(exc_info.value)