bytedance/deer-flow · error · Mem0APIError
mem0 {method} {path} returned malformed JSON: {e}
Error message
mem0 {method} {path} returned malformed JSON: {e} What it means
Raised as Mem0APIError by Mem0Client._request when the server returns HTTP < 400 with a non-empty body that is not valid JSON (json.JSONDecodeError on resp.json()). The client expects JSON responses ('Accept: application/json'); malformed JSON means something other than the real mem0 API answered — or the response stream was corrupted/truncated.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/mem0/client.py:59
def close(self) -> None:
self._http.close()
def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]:
try:
resp = self._http.request(method, path, **kwargs)
except httpx.HTTPError as e:
raise Mem0APIError(f"mem0 request failed: {e}") from e
if resp.status_code == 401:
raise Mem0AuthError("mem0 authentication failed (check the API key)")
if resp.status_code >= 400:
raise Mem0APIError(f"mem0 {method} {path} -> {resp.status_code}: {resp.text[:200]}")
if not resp.content:
return {}
try:
return resp.json()
except json.JSONDecodeError as e:
raise Mem0APIError(f"mem0 {method} {path} returned malformed JSON: {e}") from e
def add_memories(
self,
*,
messages: list[dict[str, str]],
user_id: str | None = None,
agent_id: str | None = None,
run_id: str | None = None,
) -> dict[str, Any]:
"""Queue extraction (async server-side; response carries an event_id)."""
body: dict[str, Any] = {"messages": messages}
if user_id:
body["user_id"] = user_id
if agent_id:
body["agent_id"] = agent_id
if run_id:
body["run_id"] = run_id
return self._request("POST", "/v3/memories/add/", json=body)View on GitHub (pinned to 1dd6ba1acb)
Solutions
- curl the base_url from the Gateway host and inspect Content-Type/body — if you get HTML, the URL or the proxy is wrong
- Fix base_url to point directly at the mem0 API root, bypassing any UI-serving host or path
- Exclude the mem0 host from corporate proxy interception (NO_PROXY) or configure the proxy correctly
- If self-hosted behind nginx/ingress, verify the route proxies to the mem0 service and passes Accept/Content-Type headers untouched
Example fix
# before export HTTPS_PROXY=http://proxy.corp:3128 # intercepts api.mem0.ai, returns HTML # after export HTTPS_PROXY=http://proxy.corp:3128 export NO_PROXY=api.mem0.ai # or fix base_url to the real API host
Defensive patterns
Strategy: try-catch
Validate before calling
import httpx
def mem0_returns_json(base_url: str) -> bool:
try:
r = httpx.get(base_url, timeout=5, headers={"Accept": "application/json"})
ct = r.headers.get("content-type", "")
return "json" in ct or r.content[:1] in (b"{", b"[")
except httpx.HTTPError:
return False Try / catch
from deerflow.agents.memory.backends.mem0.client import Mem0APIError
try:
data = client.get_context(user_id=u)
except Mem0APIError as e:
if "malformed JSON" in str(e):
# something other than the mem0 API answered (proxy/captive portal/wrong URL)
# do NOT retry — diagnose the base_url/proxy path first
raise RuntimeError(f"non-API endpoint answered at base_url: {e}") from e
raise Prevention
- Smoke-test base_url with curl -H 'Accept: application/json' and confirm a JSON body before enabling the backend
- Exclude the mem0 host from intercepting proxies (NO_PROXY) in corporate networks
- Self-hosted: verify ingress routes the API prefix to the mem0 service, not a UI/static server
When it happens
Trigger: A request succeeds status-wise but the body is HTML (captive portal, proxy error page, a reverse proxy serving the frontend on the same host), a truncated response from a flaky proxy, or a misconfigured base_url landing on a non-API server.
Common situations: Corporate proxy or Wi-Fi captive portal intercepting HTTPS and returning an HTML page; base_url pointing at a web UI instead of the API; self-hosted ingress misrouting /memories traffic to a static server; response compression handled incorrectly by an intermediate proxy.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Honcho returned non-JSON response: POST {path}: {exc}
- mem0 request failed: {e}
- mem0 {method} {path} -> {resp.status_code}: {resp.text[:200]
- agents_api.enabled
- Failed to create agent: ${res.statusText}
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/ba62eae1b4bacea1.
Report an issue: GitHub.