Skip to content

Workflow builder allows saving with multiple start nodes (runtime fails generically as 'Failed to execute text chat assistant turn') #378

@stefandsl

Description

@stefandsl

What

The workflow builder (ui/src/components/flow/AddNodePanel.tsx + ui/src/app/workflow/[workflowId]/hooks/useWorkflowState.ts) allows the user to add a second startCall node to a workflow and save it. The backend validator enforces "exactly one start" only at execute time, and the error is wrapped in a generic TextChatSessionExecutionError("Failed to execute text chat assistant turn") (api/services/workflow/text_chat_session_service.py:209), so when the user triggers a chat or call the failure message gives no hint about the real cause.

Concrete failure mode encountered: a Telegram bot voice/chat flow on a workflow with two starts returned Dograh API 500: {"detail":"Failed to execute text chat assistant turn"}. The actual cause — "Workflow has 2 start nodes — exactly one is required" — was only surfaceable by reading workflow_run_text_sessions.session_data directly.

Repro

  1. Open any workflow in the builder.
  2. Click "Add node" → Triggers → "Start Call". A second startCall is silently added.
  3. Save (Cmd/Ctrl+S). Save succeeds without complaint.
  4. Trigger any execution (text chat in the agent tester, voice call via Telegram bot, etc.).
  5. Get the generic 500.

Why it happens

  • AddNodePanel has no conditional on existing nodes; the trigger button is always clickable.
  • saveWorkflow ships whatever's in the store; no client-side preflight for graph invariants.
  • The execute-time validator's message is correct and specific, but the wrapper in execute_pending_text_chat_turn drops it from the HTTP response detail.

Suggested fix

I've opened a PR on my fork doing two things — happy to upstream it if useful:

  1. AddNodePanel: disable any spec in the trigger category when one already exists on the canvas, with a tooltip explaining why. Matches Activepieces' "one trigger, replace-in-place" pattern. (Zapier does the same; n8n is the multi-trigger outlier but their data model is built for it — Dograh's isn't.)
  2. saveWorkflow: belt-and-suspenders client-side preflight that toasts and refuses to save when triggerCount > 1, so paste/import flows don't slip past.

A separate small fix is also worth doing on the API side: include the original exception message in TextChatSessionExecutionError so the 500 response detail is debuggable without DB access. (My fork has this as a separate PR — see stefandsl/dograh#25.)

Out of scope but worth thinking about

A "Replace trigger" affordance on the existing start node (Activepieces-style pencil icon) would let users swap trigger types without the "delete first, add second" two-step.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions