{"record":{"id":"45df784fbbb99d43","repo":"bytedance/deer-flow","slug":"mem0-authentication-failed-check-the-api-key","errorCode":null,"errorMessage":"mem0 authentication failed (check the API key)","messagePattern":"mem0 authentication failed \\(check the API key\\)","errorType":"exception","errorClass":"Mem0AuthError","httpStatus":null,"severity":"error","filePath":"backend/packages/harness/deerflow/agents/memory/backends/mem0/client.py","lineNumber":51,"sourceCode":"        transport: httpx.BaseTransport | None = None,\n    ) -> None:\n        self._http = httpx.Client(\n            base_url=base_url.rstrip(\"/\"),\n            headers={\"Authorization\": f\"Token {api_key}\", \"Accept\": \"application/json\"},\n            timeout=timeout_seconds,\n            transport=transport,\n        )\n\n    def close(self) -> None:\n        self._http.close()\n\n    def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]:\n        try:\n            resp = self._http.request(method, path, **kwargs)\n        except httpx.HTTPError as e:\n            raise Mem0APIError(f\"mem0 request failed: {e}\") from e\n        if resp.status_code == 401:\n            raise Mem0AuthError(\"mem0 authentication failed (check the API key)\")\n        if resp.status_code >= 400:\n            raise Mem0APIError(f\"mem0 {method} {path} -> {resp.status_code}: {resp.text[:200]}\")\n        if not resp.content:\n            return {}\n        try:\n            return resp.json()\n        except json.JSONDecodeError as e:\n            raise Mem0APIError(f\"mem0 {method} {path} returned malformed JSON: {e}\") from e\n\n    def add_memories(\n        self,\n        *,\n        messages: list[dict[str, str]],\n        user_id: str | None = None,\n        agent_id: str | None = None,\n        run_id: str | None = None,\n    ) -> dict[str, Any]:\n        \"\"\"Queue extraction (async server-side; response carries an event_id).\"\"\"","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/packages/harness/deerflow/agents/memory/backends/mem0/client.py#L33-L69","documentation":"Raised as Mem0AuthError by Mem0Client._request when the mem0 server answers HTTP 401. The client authenticates with an 'Authorization: Token <key>' header, where the key comes from the environment variable named by api_key_env (default MEM0_API_KEY) via Mem0Config.resolve_api_key. A 401 means a response was received but the presented token was rejected — wrong, expired, or revoked key.","triggerScenarios":"Any Mem0Client request when the resolved API key is invalid: MEM0_API_KEY holds a stale/revoked platform key, api_key_env points at the wrong env var that happens to contain another service's key, or the key belongs to a different mem0 environment than base_url targets.","commonSituations":"Rotated the mem0 API key in the dashboard but did not update the env var in the Gateway process; renamed the env var in config but kept the old name deployed; copied a key from a different mem0 project/org; trailing whitespace/newline pasted into the env var value (resolve_api_key strips whitespace, but a wrong key is still wrong).","solutions":["Verify the key: re-copy the current API key from the mem0 dashboard and set it in the env var named by api_key_env (default MEM0_API_KEY), then restart the Gateway","Confirm api_key_env matches the variable actually exported in the Gateway's environment (config api_key_env vs deployed env var name)","Confirm base_url matches the environment (platform vs self-hosted) the key was issued for","mem0 startup_policy: fail_fast (default) runs an auth check at config load — use it so a bad key fails at boot, not mid-conversation"],"exampleFix":"# before\nexport MEM0_API_KEY=\"m0-sk-old-revoked-key\"\n\n# after\nexport MEM0_API_KEY=\"m0-sk-current-valid-key\"   # re-copied from mem0 dashboard","handlingStrategy":"validation","validationCode":"import os\n\ndef mem0_credentials_present(api_key_env: str = \"MEM0_API_KEY\") -> bool:\n    return bool(os.environ.get(api_key_env, \"\").strip())\n\n# With startup_policy: fail_fast (default), the backend performs a real auth\n# check at config load — prefer that over hand-rolled checks.","typeGuard":null,"tryCatchPattern":"from deerflow.agents.memory.backends.mem0.client import Mem0AuthError\n\ntry:\n    client.search(query=\"ping\", user_id=u)\nexcept Mem0AuthError:\n    alert(\"mem0 API key rejected — rotate MEM0_API_KEY and restart\")\n    raise","preventionTips":["Keep startup_policy: fail_fast (the default) so an invalid key fails Gateway boot instead of mid-conversation","Store the key in a secret manager / env injection, never in config.yaml (only the env var NAME goes in config via api_key_env)","After rotating a mem0 key, restart the Gateway process so the new env var value is read"],"tags":["mem0","memory","authentication","api-key","http-401"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}