{"record":{"id":"f90447c61780d4fe","repo":"bytedance/deer-flow","slug":"failed-to-update-memory-fact","errorCode":null,"errorMessage":"Failed to update memory fact.","messagePattern":"Failed to update memory fact\\.","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"backend/app/gateway/routers/memory.py","lineNumber":390,"sourceCode":"    try:\n        memory_data = await asyncio.to_thread(\n            manager.update_fact,\n            fact_id=fact_id,\n            content=request.content,\n            category=request.category,\n            confidence=request.confidence,\n            user_id=_resolve_memory_user_id(http_request),\n        )\n    except NotImplementedError:\n        raise _unsupported_501(manager, \"update fact\") from None\n    except ValueError as exc:\n        raise _map_memory_fact_value_error(exc) from exc\n    except KeyError as exc:\n        raise HTTPException(status_code=404, detail=f\"Memory fact '{fact_id}' not found.\") from exc\n    except (MemoryConflictError, MemoryCorruptionError) as exc:\n        raise _map_memory_manager_error(exc) from exc\n    except OSError as exc:\n        raise HTTPException(status_code=500, detail=\"Failed to update memory fact.\") from exc\n\n    return MemoryResponse(**memory_data)\n\n\n@router.get(\n    \"/memory/export\",\n    response_model=MemoryResponse,\n    response_model_exclude_none=True,\n    summary=\"Export Memory Data\",\n    description=\"Export the current global memory data as JSON for backup or transfer.\",\n)\nasync def export_memory(http_request: Request) -> MemoryResponse:\n    \"\"\"Export the current memory data.\"\"\"\n    manager = await asyncio.to_thread(get_memory_manager)\n    memory_data = await _get_memory_or_501(manager, _resolve_memory_user_id(http_request), \"export memory\")\n    return MemoryResponse(**memory_data)\n\n","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/memory.py#L372-L408","documentation":"Raised as HTTP 500 by PATCH /memory/facts/{fact_id} when manager.update_fact fails with an OSError while writing the updated store. Distinct from 404 (fact missing), 4xx validation (ValueError), and conflict/corruption errors which are mapped separately.","triggerScenarios":"PATCH /api/memory/facts/{fact_id} with a valid body while the memory backend cannot persist changes: read-only mount, disk full, or file lock contention.","commonSituations":"Read-only Docker volume for the memory store; SELinux denying writes; multiple Gateway replicas sharing one store path without coordination.","solutions":["Inspect the chained OSError in Gateway logs for the failing path and errno.","Fix filesystem permissions/ownership on the memory store directory and ensure it is mounted read-write.","Free disk space or raise the volume size quota.","Route each Gateway instance to its own memory store path if replicas run concurrently."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"assert os.access(MEMORY_STORE_DIR, os.W_OK), \"memory store not writable before patch\"","typeGuard":null,"tryCatchPattern":"resp = requests.patch(f\"{BASE}/api/memory/facts/{fact_id}\", json=patch)\nif resp.status_code == 500 and \"Failed to update\" in resp.json().get(\"detail\", \"\"):\n    retry_with_backoff(max_attempts=3)  # transient filesystem failure\nelif resp.status_code == 404:\n    handle_missing_fact(fact_id)\nelif resp.status_code == 409:\n    handle_conflict(resp)","preventionTips":["Health-check the store directory writability at deploy time.","Avoid concurrent patch requests to the same fact from multiple clients.","Alert on any 500 from memory endpoints — they indicate store-level problems, not client bugs."],"tags":["memory","filesystem","http-500","gateway"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}