bytedance/deer-flow · warning · HTTPException
Memory fact '{fact_id}' not found.
Error message
Memory fact '{fact_id}' not found. What it means
404 raised when delete_fact raises KeyError: no fact with the given fact_id exists for the resolved user. Memory is per-user isolated (_resolve_memory_user_id), so a fact id that exists for another user is equally 'not found'.
Source
Thrown at backend/app/gateway/routers/memory.py:353
return MemoryResponse(**memory_data)
@router.delete(
"/memory/facts/{fact_id}",
response_model=MemoryResponse,
response_model_exclude_none=True,
summary="Delete Memory Fact",
description="Delete a single saved memory fact by its fact id.",
)
async def delete_memory_fact_endpoint(fact_id: str, http_request: Request) -> MemoryResponse:
"""Delete a single fact from memory by fact id."""
manager = await asyncio.to_thread(get_memory_manager)
try:
memory_data = await asyncio.to_thread(manager.delete_fact, fact_id, user_id=_resolve_memory_user_id(http_request))
except NotImplementedError:
raise _unsupported_501(manager, "delete fact") from None
except KeyError as exc:
raise HTTPException(status_code=404, detail=f"Memory fact '{fact_id}' not found.") from exc
except (MemoryConflictError, MemoryCorruptionError) as exc:
raise _map_memory_manager_error(exc) from exc
except OSError as exc:
raise HTTPException(status_code=500, detail="Failed to delete memory fact.") from exc
return MemoryResponse(**memory_data)
@router.patch(
"/memory/facts/{fact_id}",
response_model=MemoryResponse,
response_model_exclude_none=True,
summary="Patch Memory Fact",
description="Partially update a single saved memory fact by its fact id while preserving omitted fields.",
)
async def update_memory_fact_endpoint(fact_id: str, request: FactPatchRequest, http_request: Request) -> MemoryResponse:
"""Partially update a single fact manually."""
manager = await asyncio.to_thread(get_memory_manager)View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Re-fetch the current fact list (GET /api/memory) and delete using a fresh id
- Treat 404 on delete as success if the goal is the fact being gone (idempotent delete handling)
- Confirm the request carries the same user identity that created the fact
Example fix
// before
await fetch(`/api/memory/facts/${id}`, {method:'DELETE'}).then(r => { if (!r.ok) throw new Error('delete failed'); });
// after
const res = await fetch(`/api/memory/facts/${id}`, {method:'DELETE'});
if (res.status === 404) { console.info('fact already removed'); return; }
if (!res.ok) throw new Error('delete failed'); Defensive patterns
Strategy: try-catch
Validate before calling
const mem = await getMemory(); if (!mem.facts?.[factId]) { console.info('fact already absent'); return; } // proceed to DELETE Type guard
function factExists(factId: string, memory: {facts?: Record<string, unknown>}): boolean { return Boolean(memory.facts && factId in memory.facts); } Try / catch
try { await deleteFact(id); } catch (e) { if (e.status === 404) return; /* already gone — treat as success */ throw e; } Prevention
- Handle delete-404 as success (idempotent delete semantics)
- Refresh the fact list before offering delete actions in the UI
- Debounce double-clicks on delete buttons to avoid duplicate requests
When it happens
Trigger: DELETE /api/memory/facts/{fact_id} with an id from an outdated UI list; deleting a fact already removed by a concurrent request or by the agent itself; sending a fact id belonging to a different user; malformed id strings that never match stored keys.
Common situations: Stale frontend lists after background memory maintenance; double-click delete firing two requests; id copy errors (truncated UUIDs); switching authenticated users while reusing cached fact ids.
Related errors
- No feedback found for this run
- Feedback {feedback_id} not found
- File not found: {filename}
- 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/fd282b23f6658cc9.
Report an issue: GitHub.