langflow-ai/langflow · error · HTTPException

Flow creation failed.

Error message

Flow creation failed.

What it means

Raised when _new_flow successfully created a Flow and the session committed, but an immediate session.get(Flow, created.id) returned None. This indicates an inconsistency inside the same session/transaction (e.g. the commit silently rolled back, a flush issue, or a DB isolation anomaly), not user error. The 500 reflects that the just-created row vanished.

Source

Thrown at src/backend/base/langflow/agentic/utils/assistant_runner.py:61

        if flow is None or (flow.user_id is not None and str(flow.user_id) != str(user_id)):
            raise HTTPException(status_code=404, detail="Flow not found.")
        return flow, False

    folder = await get_or_create_default_folder(session, user_id)
    new_flow = FlowCreate(
        name=DEFAULT_FLOW_NAME,
        description="Created by the Langflow Assistant via MCP",
        data={"nodes": [], "edges": []},
        folder_id=folder.id,
        user_id=user_id,
    )
    storage_service = get_storage_service()
    created = await _new_flow(session=session, flow=new_flow, user_id=user_id, storage_service=storage_service)
    await session.commit()
    # _new_flow returns a FlowRead; re-fetch the ORM row so later edits persist.
    db_flow = await session.get(Flow, created.id)
    if db_flow is None:
        raise HTTPException(status_code=500, detail="Flow creation failed.")
    return db_flow, True


class _CanvasState:
    """Fallback event replay for headless runs when no working-flow snapshot exists.

    Handles ``set_flow`` / ``add_component`` / ``connect``. The authoritative
    source is the server-side working flow (it captures configure/remove/
    tool-mode/select-output too); this replay only runs when that snapshot is
    unavailable. ``changed`` flips on ANY ``flow_update`` so persistence is
    gated on "the agent mutated the canvas", not on the subset replayed here.
    """

    def __init__(self, initial_data: dict[str, Any] | None) -> None:
        self.data: dict[str, Any] = copy.deepcopy(initial_data) if initial_data else {}
        self.data.setdefault("nodes", [])
        self.data.setdefault("edges", [])
        self.name: str | None = None

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Retry the assistant call — a transient isolation anomaly usually does not recur.
  2. Inspect backend logs around the commit for warnings from SQLAlchemy event listeners or the storage service.
  3. If reproducible, check for a database trigger or after-commit hook deleting new flows.
Defensive patterns

Strategy: retry

Try / catch

try:
    result = await run_assistant(...)
except HTTPError as e:
    if e.response.status_code == 500 and "Flow creation failed" in e.response.text:
        result = await run_assistant(...)  # one retry; invariant break is typically transient
    else:
        raise

Prevention

When it happens

Trigger: Race where another process deletes the row between commit and re-fetch; a session whose commit was vetoed by a listener/extension; exotic SQLite/database locking behavior under concurrency.

Common situations: Very rare — effectively a backend invariant violation; most often seen with custom SQLAlchemy session instrumentation or aggressive concurrent cleanup jobs.

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/d47f153c4d1db96e. Report an issue: GitHub.