langflow-ai/langflow · error · HTTPException

Unexpected error

Error message

Unexpected error: {exc!s}

What it means

Final catch-all in the flow-events handler: any exception other than JobQueueNotFoundError and non-HTTPException types is logged with aexception and re-raised as 500 'Unexpected error: {exc!s}'. HTTPExceptions raised inside the inner try are re-raised untouched (explicit isinstance check).

Solutions

  1. Read the aexception traceback in the logs — the detail string alone rarely identifies the failing branch.
  2. If it recurs after an upgrade, clear old job/event keys in Redis so stale-schema events are not replayed.
  3. Report with the traceback if the failure is inside Langflow's own event pipeline.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    events = await get_flow_events(job_id)
except HTTPError as e:
    if e.response.status_code == 500 and "Unexpected error" in e.response.text:
        capture_server_logs(job_id)  # aexception logged the real traceback server-side
        raise
    raise

Prevention

When it happens

Trigger: Failures while consuming the event stream: queue decode errors (value.decode('utf-8') on corrupt data), event_manager callback exceptions, asyncio primitives misbehaving, or bugs in delivery-mode-specific branches.

Common situations: Corrupt queue payloads after a version upgrade changed the event schema; bugs in custom event-manager extensions; Redis returning unexpected types.

Related errors


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

Appendix: source

Thrown at src/backend/base/langflow/api/build.py:327

            # Return as NDJSON format - each line is a complete JSON object
            content = "\n".join([event for event in events if event is not None])
            return Response(content=content, media_type="application/x-ndjson")
        except asyncio.CancelledError as exc:
            await logger.ainfo(f"Event polling was cancelled for job {job_id}")
            raise HTTPException(status_code=499, detail="Event polling was cancelled") from exc
        except asyncio.TimeoutError:
            await logger.awarning(f"Timeout while waiting for events for job {job_id}")
            return Response(content="", media_type="application/x-ndjson")  # Return empty response instead of error

    except JobQueueNotFoundError as exc:
        await logger.aerror(f"Job not found: {job_id}. Error: {exc!s}")
        raise HTTPException(status_code=404, detail=f"Job not found: {exc!s}") from exc
    except Exception as exc:
        if isinstance(exc, HTTPException):
            raise
        await logger.aexception(f"Unexpected error processing flow events for job {job_id}")
        raise HTTPException(status_code=500, detail=f"Unexpected error: {exc!s}") from exc


async def create_flow_response(
    queue: asyncio.Queue,
    event_manager: EventManager,
    event_task: asyncio.Task | None,
    *,
    queue_service: JobQueueService | None = None,
    job_id: str | None = None,
) -> DisconnectHandlerStreamingResponse:
    """Create a streaming response for the flow build process.

    When *queue_service* and *job_id* are provided and the service exposes a
    ``signal_cancel`` method (RedisJobQueueService with cancel_channel_enabled),
    a client disconnect on a non-owner worker (``event_task is None``) publishes
    a cross-worker cancel so the producer worker stops emitting events promptly
    instead of running the build to natural completion.
    """

View on GitHub (pinned to 976ec789d2)