bytedance/deer-flow · error · HTTPException

Failed to delete local thread data.

Error message

Failed to delete local thread data.

What it means

Raised by DELETE /threads/{thread_id} when deleting the thread's on-disk data directory raises an unexpected exception (anything other than ValueError, which maps to 422, or FileNotFoundError, which is treated as success). The endpoint delegates to path_manager.delete_thread_dir(thread_id, user_id=user_id); an OSError from the filesystem surfaces here as a 500. The full traceback is logged via logger.exception before the HTTPException is raised.

Source

Thrown at backend/app/gateway/routers/threads.py:541

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _delete_thread_data(thread_id: str, paths: Paths | None = None, *, user_id: str | None = None) -> ThreadDeleteResponse:
    """Delete local persisted filesystem data for a thread."""
    path_manager = paths or get_paths()
    try:
        path_manager.delete_thread_dir(thread_id, user_id=user_id)
    except ValueError as exc:
        raise HTTPException(status_code=422, detail=str(exc)) from exc
    except FileNotFoundError:
        # Not critical — thread data may not exist on disk
        logger.debug("No local thread data to delete for %s", sanitize_log_param(thread_id))
        return ThreadDeleteResponse(success=True, message=f"No local data for {thread_id}")
    except Exception as exc:
        logger.exception("Failed to delete thread data for %s", sanitize_log_param(thread_id))
        raise HTTPException(status_code=500, detail="Failed to delete local thread data.") from exc

    logger.info("Deleted local thread data for %s", sanitize_log_param(thread_id))
    return ThreadDeleteResponse(success=True, message=f"Deleted local thread data for {thread_id}")


async def _fetch_raw_pending_writes(checkpointer: Any, config: dict[str, Any]) -> list[Any]:
    """Fetch pending writes attached to a specific checkpoint.

    Snapshot ``tasks`` only reflect writes that were pending while a task was
    still scheduled; writes attached to the latest checkpoint afterwards
    (rollback reattachment, worker error fallback) never surface there, so the
    status derivation needs one raw tuple fetch on the resolved checkpoint.
    """
    raw_tuple = await checkpointer.aget_tuple(config)
    if raw_tuple is None:
        return []
    return list(getattr(raw_tuple, "pending_writes", ()) or ())

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Check the Gateway logs for the logger.exception('Failed to delete thread data for %s') traceback — it names the exact OSError and path class involved.
  2. Verify the Gateway process user owns or can write the configured thread data root (check config.yaml persistence paths) — fix ownership with chown -R on the data dir.
  3. Retry the DELETE once transient filesystem conditions (lock, mount flap) clear; confirm no other process (backup job, another Gateway replica) is traversing the dir.
  4. If it recurs on a specific thread, inspect that thread's directory manually and remove it by hand, then re-issue the DELETE (FileNotFoundError path then returns success).
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await fetch(`/api/threads/${id}`, {method: 'DELETE'});
} catch (e) {
  // network-level failure only; HTTP 500 arrives as a normal response
} 
// on 500: surface 'deletion failed, retry' and keep the thread in the list; on 404/200 remove it

Prevention

When it happens

Trigger: DELETE /api/threads/{thread_id} while the data directory or files inside it are unreadable/unwritable (PermissionError, EACCES), a path component was replaced by a file, the disk is full or read-only, or an external process holds/locks files during deletion on Windows-style mounts.

Common situations: Data dir created by root in a container then served by a non-root user; volume permission drift after chown/chmod; NFS/FUSE mounts returning EIO; concurrent deletion races where a rmtree partially fails after FileNotFoundError of an inner entry was handled but other inner errors are not.

Related errors


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