bytedance/deer-flow · error · HTTPException

Failed to create thread

Error message

Failed to create thread

What it means

Raised by the goal-ensure helper when thread_store.create(thread_id, metadata={}) fails while materializing a thread record for a goal PUT. This is the metadata-store write path (SQL or memory store); any exception during INSERT — connectivity, schema drift, constraint violation — is logged and converted to a 500 'Failed to create thread'.

Source

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

    thread_store = get_thread_store(request)
    checkpointer = get_checkpointer(request)
    thread_owner_user_id = get_trusted_internal_owner_user_id(request)
    thread_owner_kwargs = {"user_id": thread_owner_user_id} if thread_owner_user_id else {}

    record = await thread_store.get(thread_id, **thread_owner_kwargs)
    if record is None and thread_owner_user_id:
        unscoped_record = await thread_store.get(thread_id, user_id=None)
        if unscoped_record is not None:
            if unscoped_record.get("user_id") != thread_owner_user_id:
                await thread_store.update_owner(thread_id, thread_owner_user_id, user_id=None)
            record = await thread_store.get(thread_id, **thread_owner_kwargs)
    if record is None:
        try:
            await thread_store.create(thread_id, metadata={}, **thread_owner_kwargs)
        except Exception:
            logger.exception("Failed to create thread_meta for goal thread %s", sanitize_log_param(thread_id))
            raise HTTPException(status_code=500, detail="Failed to create thread") from None

    try:
        await ensure_thread_checkpoint(checkpointer, thread_id)
    except Exception:
        logger.exception("Failed to create goal checkpoint for thread %s", sanitize_log_param(thread_id))
        raise HTTPException(status_code=500, detail="Failed to create thread checkpoint") from None


# ---------------------------------------------------------------------------
# Endpoints
# ---------------------------------------------------------------------------


@router.delete("/{thread_id}", response_model=ThreadDeleteResponse)
@require_permission("threads", "delete", owner_check=True, require_existing=True)
async def delete_thread_data(thread_id: str, request: Request) -> ThreadDeleteResponse:
    """Delete local persisted filesystem data for a thread.

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Read the logged 'Failed to create thread_meta for goal thread %s' traceback to identify the underlying driver error.
  2. Verify database connectivity and that migrations are current (backend make migrate-rev / app startup migration step).
  3. If it is a duplicate-key race, retry the PUT — the second attempt takes the existing-record path and succeeds.
  4. Confirm the thread_id is a plain UUID string; malformed ids that survive validation but break store constraints show up here.
Defensive patterns

Strategy: retry

Validate before calling

const healthy = await fetch('/api/health').ok;
if (!healthy) { /* defer goal PUT until Gateway/db is up */ }

Try / catch

try { await api.put(`/threads/${id}/goal`, body); }
catch (err) {
  if (err.status === 500 && /Failed to create thread/.test(err.detail)) await delayThenRetryOnce();
  else throw err;
}

Prevention

When it happens

Trigger: PUT /api/threads/{thread_id}/goal for a thread_id that has no thread_meta row while the database is unreachable, the thread_meta table is missing (migrations not run), or a duplicate-key/uniqueness error occurs on INSERT.

Common situations: Postgres/SQLite down or credentials rotated; alembic/db migrations not applied after upgrade so the thread_meta table or columns don't match; racing two PUT /goal calls for the same brand-new thread id where the loser's INSERT hits the primary key.

Related errors


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