bytedance/deer-flow · error · HTTPException

Failed to create memory fact.

Error message

Failed to create memory fact.

What it means

500 raised when creating a single memory fact hits OSError at the persistence layer. The fact-creation call itself succeeded logically; writing the updated memory store to disk failed with an I/O error (permissions, disk full, lock contention at OS level). Distinct from the 409 cap case and the ValueError validation path.

Source

Thrown at backend/app/gateway/routers/memory.py:330

async def create_memory_fact_endpoint(request: FactCreateRequest, http_request: Request) -> MemoryResponse:
    """Create a single fact manually."""
    manager = await asyncio.to_thread(get_memory_manager)
    try:
        memory_data, fact_id = await asyncio.to_thread(
            manager.create_fact,
            content=request.content,
            category=request.category,
            confidence=request.confidence,
            user_id=_resolve_memory_user_id(http_request),
        )
    except NotImplementedError:
        raise _unsupported_501(manager, "create fact") from None
    except ValueError as exc:
        raise _map_memory_fact_value_error(exc) 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 create memory fact.") from exc

    if fact_id is None:
        # max_facts cap evicted the new (lower-confidence) fact; it was not stored.
        raise HTTPException(status_code=409, detail="Fact was not stored because memory.max_facts kept higher-confidence facts")
    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:

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Inspect the chained OSError in Gateway logs (path and errno)
  2. Repair write permissions on the memory store path and free disk space
  3. If caused by a second process locking the file, isolate the memory path per Gateway instance
  4. Retry the fact creation after remediation — the write is atomic, so no partial fact is left behind

Example fix

# before: docker-compose mounts memory volume read-only -> every POST /memory/facts -> 500
# after
volumes:
  - ./data/memory:/data/memory   # remove :ro flag, ensure ownership matches Gateway user
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try { return await createFact(body); } catch (e) { if (e.status === 500 && /Failed to create memory fact/.test(e.detail)) { await delay(backoff(attempt++)); if (attempt <= 2) return createFact(body); } throw e; }

Prevention

When it happens

Trigger: POST /api/memory/facts while the memory file cannot be written (read-only mount, permission change after startup); disk-full conditions; antivirus/SCIM intercepting the write on the host.

Common situations: Memory directory created by root during setup but the Gateway drops privileges afterwards; long-running processes holding the memory file; disk quota exhaustion on shared hosts.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/4457e42f307b341c. Report an issue: GitHub.