{"record":{"id":"f3cc8dc0f975e092","repo":"bytedance/deer-flow","slug":"failed-to-delete-memory-fact","errorCode":null,"errorMessage":"Failed to delete memory fact.","messagePattern":"Failed to delete memory fact\\.","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"backend/app/gateway/routers/memory.py","lineNumber":357,"sourceCode":"    \"/memory/facts/{fact_id}\",\n    response_model=MemoryResponse,\n    response_model_exclude_none=True,\n    summary=\"Delete Memory Fact\",\n    description=\"Delete a single saved memory fact by its fact id.\",\n)\nasync def delete_memory_fact_endpoint(fact_id: str, http_request: Request) -> MemoryResponse:\n    \"\"\"Delete a single fact from memory by fact id.\"\"\"\n    manager = await asyncio.to_thread(get_memory_manager)\n    try:\n        memory_data = await asyncio.to_thread(manager.delete_fact, fact_id, user_id=_resolve_memory_user_id(http_request))\n    except NotImplementedError:\n        raise _unsupported_501(manager, \"delete fact\") from None\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 delete memory fact.\") from exc\n\n    return MemoryResponse(**memory_data)\n\n\n@router.patch(\n    \"/memory/facts/{fact_id}\",\n    response_model=MemoryResponse,\n    response_model_exclude_none=True,\n    summary=\"Patch Memory Fact\",\n    description=\"Partially update a single saved memory fact by its fact id while preserving omitted fields.\",\n)\nasync def update_memory_fact_endpoint(fact_id: str, request: FactPatchRequest, http_request: Request) -> MemoryResponse:\n    \"\"\"Partially update a single fact manually.\"\"\"\n    manager = await asyncio.to_thread(get_memory_manager)\n    try:\n        memory_data = await asyncio.to_thread(\n            manager.update_fact,\n            fact_id=fact_id,","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/memory.py#L339-L375","documentation":"Raised as HTTP 500 by the DELETE /memory/facts/{fact_id} endpoint when the underlying memory manager's delete_fact call fails with an OSError. The memory backend is filesystem-based, so this signals an I/O failure while persisting the deletion (disk full, permission denied, missing/corrupted store file), not a bad request.","triggerScenarios":"Calling DELETE /api/memory/facts/{fact_id} (or the same route through nginx /api proxy) while the memory store directory is unwritable, the JSON backing file is locked by another process, the disk is full, or the store path was deleted mid-request.","commonSituations":"Running the Gateway as a user without write access to the memory store directory; container volume mount read-only; disk exhaustion; concurrent Gateway processes writing the same store file.","solutions":["Check Gateway logs for the chained OSError (raise ... from exc preserves it) to see the exact errno and path.","Verify write permission and free space on the memory store directory configured for the memory backend.","Ensure only one Gateway instance writes to the same memory store path.","If the store file is corrupted, restore from a /memory/export backup and retry the delete."],"exampleFix":"# before: memory store dir owned by root after a volume mount\nsudo chown -R appuser:appgroup /var/lib/deerflow/memory\n# after: delete succeeds once the process can write the store\n# curl -X DELETE http://localhost:2026/api/memory/facts/<fact_id>","handlingStrategy":"retry","validationCode":"import os\nSTORE_DIR = get_memory_store_path_from_config()  # the configured memory store location\nassert os.path.isdir(STORE_DIR), f\"missing store dir {STORE_DIR}\"\nassert os.access(STORE_DIR, os.W_OK), f\"store dir not writable: {STORE_DIR}\"","typeGuard":null,"tryCatchPattern":"try:\n    resp = requests.delete(f\"{BASE}/api/memory/facts/{fact_id}\")\nexcept requests.RequestException:\n    raise  # transport error, not the 500\nif resp.status_code >= 500:\n    log_and_retry_with_backoff(resp)  # transient I/O: inspect detail + server logs\nelif resp.status_code == 404:\n    pass  # already gone — treat delete as idempotent success","preventionTips":["Mount the memory store volume read-write and verify the Gateway process owns it.","Monitor disk space on the data volume; OSError on write is usually ENOSPC or EACCES.","Run exactly one writer process per memory store path.","Keep periodic /memory/export backups so a failed write never costs data."],"tags":["memory","filesystem","http-500","gateway"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}