bytedance/deer-flow · error · HTTPException

Thread metadata store not available

Error message

Thread metadata store not available

What it means

HTTP 503 from get_thread_store() when request.app.state.thread_store is None. The thread metadata store (SQL or memory-backed) is created during Gateway lifespan; this error means thread-persistence infrastructure was never attached, so all thread listing/metadata routes fail.

Source

Thrown at backend/app/gateway/deps.py:640

get_stream_bridge: Callable[[Request], StreamBridge] = _require("stream_bridge", "Stream bridge")
get_run_manager: Callable[[Request], RunManager] = _require("run_manager", "Run manager")
get_checkpointer: Callable[[Request], Checkpointer] = _require("checkpointer", "Checkpointer")
get_run_event_store: Callable[[Request], RunEventStore] = _require("run_event_store", "Run event store")
get_feedback_repo: Callable[[Request], FeedbackRepository] = _require("feedback_repo", "Feedback")
get_run_store: Callable[[Request], RunStore] = _require("run_store", "Run store")


def get_store(request: Request):
    """Return the global store (may be ``None`` if not configured)."""
    return getattr(request.app.state, "store", None)


def get_thread_store(request: Request) -> ThreadMetaStore:
    """Return the thread metadata store (SQL or memory-backed)."""
    val = getattr(request.app.state, "thread_store", None)
    if val is None:
        raise HTTPException(status_code=503, detail="Thread metadata store not available")
    return val


def get_scheduled_task_repo(request: Request):
    val = getattr(request.app.state, "scheduled_task_repo", None)
    if val is None:
        raise HTTPException(status_code=503, detail="Scheduled task repo not available")
    return val


def get_scheduled_task_run_repo(request: Request):
    val = getattr(request.app.state, "scheduled_task_run_repo", None)
    if val is None:
        raise HTTPException(status_code=503, detail="Scheduled task run repo not available")
    return val


def get_scheduled_task_service(request: Request):

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Check startup logs for the thread store init failure inside langgraph_runtime()
  2. Confirm the persistence backend config (config.yaml persistence section) points to a reachable database and the path/URL is correct
  3. Restart the Gateway so lifespan reconstructs and attaches thread_store
  4. In tests, use the app fixture that runs the full lifespan instead of a bare FastAPI() instance

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side preflight
const health = await fetch('/api/health');
if (!health.ok) throw new Error('Gateway not ready — thread store routes will 503');

Try / catch

try:
    threads = await client.list_threads()
except GatewayHTTPError as e:
    if e.status == 503 and 'Thread metadata store' in e.detail:
        threads = []  # optional feature unavailable
    else:
        raise

Prevention

When it happens

Trigger: Any call to thread metadata routes (list threads, get/rename/delete thread metadata) when the thread_store singleton is missing — typically because lifespan bootstrap failed (DB init error) or the route was reached on an app instance without the Gateway lifespan.

Common situations: Gateway started while the persistence database was down or its file path unwritable; running routers in isolation (pytest fixtures) without lifespan; deployment where an init container step that creates the DB was skipped.

Related errors


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