langflow-ai/langflow · error · HTTPException

Flow is not public

Error message

Flow is not public

What it means

403 from the same unauthenticated public-flow endpoint: the Flow row exists but access_type is not PUBLIC. The endpoint intentionally serves anonymous callers, so any non-public flow is refused before serialization — and secret template fields would otherwise leak, which is why the strip step only runs after this gate.

Source

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


@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."""
    actor = UserRead.model_validate(current_user, from_attributes=True)
    try:

View on GitHub (pinned to 976ec789d2)

Solutions

  1. The owner sets the flow's access to PUBLIC (flow settings / access_type) and the link works anonymously
  2. Or consume the flow with an authenticated request via GET /api/v1/flows/{flow_id} as the owner/shared user
  3. For share-link access, use the share-link route rather than the public endpoint

Example fix

# before
flow.access_type = AccessTypeEnum.PRIVATE

# after
flow.access_type = AccessTypeEnum.PUBLIC
session.add(flow)  # link now served anonymously, secrets stripped
Defensive patterns

Strategy: type-guard

Validate before calling

// Owner-side: verify visibility before distributing an anonymous link
const flow = (await axios.get(`/api/v1/flows/${flowId}`)).data;
const isPublic = flow.access_type === 'PUBLIC';

Type guard

const isPubliclyShared = (f: { access_type?: string } | undefined): f is { access_type: 'PUBLIC' } =>
  f?.access_type === 'PUBLIC';

Try / catch

catch (e) { if (e.response?.status === 403) showMakePublicPrompt(flowId); else throw e; }

Prevention

When it happens

Trigger: Loading /flows/public/{flow_id} for a flow whose access_type is PRIVATE or SESL (share-link) rather than PUBLIC; or the owner toggled it back to private after the link was shared.

Common situations: Users sharing a 'public link' that was actually a share/private link; access_type changed in the UI after the URL was distributed; expecting share-link flows to be loadable on the anonymous endpoint.

Related errors


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