bytedance/deer-flow · warning · HTTPException

Directory for '{name}' contains memory data but is not a cus

Error message

Directory for '{name}' contains memory data but is not a custom agent because config.yaml is missing; it was preserved.

What it means

HTTP 409 returned by DELETE /api/agents/{name} when the store returns 'not-custom-agent': the per-user directory for that agent exists but has no config.yaml, so it only holds memory/facts data. The delete is deliberately refused because rmtree would destroy the user's memory (regression #4279, guarded at persistence/agents/file.py:169-173).

Source

Thrown at backend/app/gateway/routers/agents.py:569

    user_id = get_effective_user_id()
    store = get_agent_store()

    try:
        # Off the event loop: file rmtree or a DB delete plus memory cleanup.
        outcome = await asyncio.to_thread(store.delete, name, user_id=user_id)
    except Exception as e:
        logger.error(f"Failed to delete agent '{name}': {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"Failed to delete agent: {str(e)}")

    if outcome == "legacy":
        raise HTTPException(
            status_code=409,
            detail=(f"Agent '{name}' only exists in the legacy shared layout and is not scoped to a user. Run scripts/migrate_user_isolation.py to move legacy agents into the per-user layout before deleting."),
        )
    if outcome == "missing":
        raise HTTPException(status_code=404, detail=f"Agent '{name}' not found")
    if outcome == "not-custom-agent":
        raise HTTPException(
            status_code=409,
            detail=(f"Directory for '{name}' contains memory data but is not a custom agent because config.yaml is missing; it was preserved."),
        )

    logger.info(f"Deleted agent '{name}'")

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Inspect users/{user_id}/agents/{name}/ under DEER_FLOW_HOME (default backend/.deer-flow) and decide whether the memory data is disposable
  2. If the agent really should be a custom agent, restore/create config.yaml in that directory, then retry the delete
  3. If the memory must be kept, move the directory aside manually (backup) and retry once the guard no longer applies
  4. Report to the user instead of auto-deleting — the 409 exists to preserve data
Defensive patterns

Strategy: validation

Validate before calling

# Check the on-disk condition the guard keys on before calling delete
from pathlib import Path
agent_dir = Path(home) / "users" / user_id / "agents" / name
if agent_dir.exists() and not (agent_dir / "config.yaml").is_file():
    print(f"'{name}' holds memory data without config.yaml; delete will be refused with 409")

Try / catch

try:
    await client.delete(f"/api/agents/{name}")
except httpx.HTTPStatusError as e:
    if e.response.status_code == 409 and "not a custom agent" in e.response.text:
        # memory-bearing directory; ask the operator, do not force
        raise RuntimeError(f"agent '{name}' holds memory data; handle manually")
    raise

Prevention

When it happens

Trigger: DELETE /api/agents/{name} where users/{user_id}/agents/{name}/ exists but config.yaml is missing — e.g. memory was written for a built-in/non-custom agent, a config.yaml was manually deleted, or a partially failed create left the directory without config.

Common situations: Agents that accrued memory data without ever being custom agents, operators who manually pruned config.yaml from the data dir, crashed/interrupted agent creation, or upgrades that changed the agent layout so config.yaml resolution moved.

Related errors


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