{"record":{"id":"6f100fb3f2fd5622","repo":"headroomlabs-ai/headroom","slug":"failed-to-update-memory-e-6f100f","errorCode":null,"errorMessage":"Failed to update memory: {e}","messagePattern":"Failed to update memory: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/memory/backends/mem0_system_adapter.py","lineNumber":280,"sourceCode":"        if user_id and existing_user_id and existing_user_id != user_id:\n            raise ValueError(\"Cannot update memories belonging to other users\")\n\n        # Build update metadata\n        now = _utcnow()\n        update_metadata: dict[str, Any] = {}\n        if reason:\n            update_metadata[\"update_reason\"] = reason\n            update_metadata[\"updated_at\"] = now.isoformat()\n\n        # Update via Mem0\n        try:\n            await asyncio.to_thread(\n                client.update,\n                memory_id=memory_id,\n                data=new_content,\n            )\n        except Exception as e:\n            raise ValueError(f\"Failed to update memory: {e}\") from e\n\n        # Fetch the updated memory\n        try:\n            updated_data = await asyncio.to_thread(client.get, memory_id=memory_id)\n        except Exception:\n            updated_data = None\n\n        if updated_data:\n            return Memory(\n                id=memory_id,\n                content=updated_data.get(\"memory\", new_content),\n                user_id=updated_data.get(\"user_id\", existing_user_id),\n                importance=0.5,  # Mem0 doesn't store importance\n                created_at=now,\n                valid_from=now,\n            )\n        else:\n            # Return a constructed memory object","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/memory/backends/mem0_system_adapter.py#L262-L298","documentation":"ValueError raised by Mem0SystemAdapter.update_memory() when the wrapped client.update(...) call (asyncio.to_thread) throws after all pre-checks passed (memory exists, ownership verified). The original exception is chained, so the '{e}' text is the real mem0/client error.","triggerScenarios":"client.update(memory_id, data) failing at the mem0 layer: transient Qdrant/network errors, collection schema drift, or mem0 API changes — reached only when the earlier client.get succeeded.","commonSituations":"Qdrant restarting mid-update; mem0 package upgraded with incompatible update() semantics; oversized new_content rejected by the backend.","solutions":["Inspect the embedded '{e}' message to identify the underlying failure","Retry the update once for transient backend/network errors — the memory was verified to exist right before","Check backend service health and collection state if errors persist","Reinstall 'headroom-ai[memory-stack]' to realign mem0 version with the adapter's expectations"],"exampleFix":"# before\nawait adapter.update_memory(mem_id, 'new text')  # ValueError: Failed to update memory: connection refused\n\n# after\nfor attempt in range(3):\n    try:\n        await adapter.update_memory(mem_id, 'new text')\n        break\n    except ValueError as e:\n        if attempt == 2 or 'connection' not in str(e):\n            raise","handlingStrategy":"retry","validationCode":"# pre-verify backend reachability to catch connection issues early\nclient = await adapter._backend._ensure_client()\nexisting = await asyncio.to_thread(client.get, memory_id=memory_id)\nassert existing, 'memory must exist before update'","typeGuard":null,"tryCatchPattern":"async def safe_update(adapter, memory_id, content, retries=2):\n    for attempt in range(retries + 1):\n        try:\n            return await adapter.update_memory(memory_id, content)\n        except ValueError as e:\n            transient = any(k in str(e) for k in ('timeout', 'connection', 'temporarily'))\n            if attempt == retries or not transient:\n                raise\n            await asyncio.sleep(2 ** attempt)","preventionTips":["Treat embedded 'connection'/'timeout' text in the wrapped message as retryable","Keep mem0 versions aligned with headroom-ai[memory-stack] to avoid API-drift update failures","Monitor update failure rates; a spike usually means backend degradation, not bad ids"],"tags":["python","mem0","update","valueerror","runtime-wrap","retryable"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}