langflow-ai/langflow · error · HTTPException

Flow not found

Error message

Flow not found

What it means

404 from the unauthenticated public-flow read endpoint (GET /api/v1/flows/public/{flow_id} or the read_public_flow handler): no Flow row with that id exists at all — this pre-check runs before the access_type check, so the id is simply unknown. Because the endpoint is anonymous, the 404 deliberately gives no ownership information.

Solutions

  1. Confirm the flow still exists via an authenticated GET /api/v1/flows/{flow_id}
  2. If it exists but you get 403 instead, the flow is PRIVATE — the owner must flip access_type to PUBLIC
  3. Regenerate/re-share the public link from the live flow
Defensive patterns

Strategy: try-catch

Validate before calling

// If authenticated: cheap existence probe before sharing an anonymous link
const exists = await axios.get(`/api/v1/flows/${flowId}`).then(() => true, (e) => e.response?.status !== 404);

Try / catch

catch (e) {
  if (e.response?.status === 404) return showLinkExpired();
  if (e.response?.status === 403) return showNotPublic();
  throw e;
}

Prevention

When it happens

Trigger: Fetching a public flow URL with a deleted flow's id, a typo'd UUID, or an id from a different environment. Comes before the 403 'Flow is not public', so existence is the only thing that failed.

Common situations: Shared/public links outliving their flow (flow deleted or DB reset); published links pointing at a dev id while served by prod; UUID truncation when copy-pasting links.

Related errors


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

Appendix: source

Thrown at src/backend/base/langflow/api/v1/flows.py:321

                    result[node.get("id")] = translated
    return result


@router.get("/public_flow/{flow_id}", response_model=FlowRead, status_code=200)
async def read_public_flow(
    *,
    session: DbSession,
    flow_id: UUID,
):
    """Read a public flow without requiring authorization (public means public).

    Because this endpoint is unauthenticated, secret field values (every template
    field marked ``password``) are stripped before returning so a PUBLIC flow does
    not leak the owner's stored API keys / credentials to anonymous callers.
    """
    flow = (await session.exec(select(Flow).where(Flow.id == flow_id))).first()
    if flow is None:
        raise HTTPException(status_code=404, detail="Flow not found")
    if flow.access_type is not AccessTypeEnum.PUBLIC:
        raise HTTPException(status_code=403, detail="Flow is not public")
    flow_read = FlowRead.model_validate(flow, from_attributes=True)
    flow_read.data = strip_secret_field_values(flow_read.data)
    return flow_read


@router.patch("/{flow_id}", response_model=FlowRead, status_code=200)
async def update_flow(
    *,
    session: DbSession,
    flow_id: UUID,
    db_flow: AuthorizedWriteFlow,
    flow: FlowUpdate,
    current_user: CurrentActiveUser,
    storage_service: Annotated[StorageService, Depends(get_storage_service)],
):
    """Update a flow."""

View on GitHub (pinned to 976ec789d2)