vxcontrol/pentagi · error

failed to submit flow input: %w

Error message

failed to submit flow input: %w

What it means

submit_flow_input's handler returned an error that is not a timeout/cancellation, not a 'flow is running' condition, and not a lost message chain — so the tool wraps and rethrows it as 'failed to submit flow input'. The input was not accepted; the wrapped error carries the specific reason. This is the generic failure bucket for the delivery step of submit_flow_input.

Source

Thrown at backend/pkg/tools/flow_manager.go:770

					"then retry %s. Use %s to confirm the flow is 'waiting' before retrying",
				StopFlowToolName, SubmitFlowInputToolName, GetFlowStatusToolName,
			), nil
		}
		// A missing message chain means the waiting subtask's execution context was lost
		// (most likely after a system restart or database cleanup while the subtask was at an ask checkpoint).
		// The subtask can no longer be resumed; the flow must be stopped and restarted.
		if strings.Contains(err.Error(), "no rows in result set") {
			return "", stateGuard(fmt.Errorf(
				"the waiting subtask's execution context is no longer available in the database — "+
					"this typically happens after a system restart when the subtask was paused at an ask checkpoint. "+
					"Recovery: (1) call %s to cancel the stale task; "+
					"(2) call %s with a fresh description of what to do next; "+
					"if the flow already has planned subtasks that should still run, "+
					"use %s to inspect the remaining plan and %s to patch it before resuming",
				StopFlowToolName, SubmitFlowInputToolName,
				GetFlowStatusToolName, PatchFlowSubtasksToolName))
		}
		return "", fmt.Errorf("failed to submit flow input: %w", err)
	}

	if waitingForAsk {
		return "Input delivered as the answer to the waiting subtask's question. The subtask will resume execution.", nil
	}

	// Input triggered task creation — wait for the generator to produce a running task.
	return t.waitForTaskReady(ctx)
}

// waitForTaskReady polls GetFlowTasks every pollInterval until a running or waiting
// task appears or pollTimeout is reached. It is called after submit_flow_input
// triggers new task creation so the LLM gets confirmation that the generator finished.
func (t *submitFlowInputTool) waitForTaskReady(ctx context.Context) (string, error) {
	deadline := time.Now().Add(t.pollTimeout)
	ticker := time.NewTicker(t.pollInterval)
	defer ticker.Stop()

View on GitHub (pinned to ea665308ba)

Solutions

  1. Inspect the wrapped error (%w) for the actual cause.
  2. Call get_flow_status to confirm the flow state before retrying.
  3. If the flow is stuck, call stop_flow and restart with a fresh submit_flow_input.
  4. Check backend logs around the handler call for the originating stack trace.

Example fix

// before: retrying the tool repeatedly without reading the cause
for i := 0; i < 3; i++ { tool.Handle(ctx, "submit_flow_input", args) }
// after: log/inspect the wrapped error first
res, err := tool.Handle(ctx, "submit_flow_input", args)
if err != nil {
    log.Printf("submit failed, cause: %v", err) // %w chain reveals root cause
}
Defensive patterns

Strategy: try-catch

Try / catch

_, err := tool.Handle(ctx, "submit_flow_input", args)
if err != nil {
    var wrapped interface{ Unwrap() error }
    if errors.As(err, &wrapped) {
        log.Printf("submit root cause: %v", errors.Unwrap(err))
    }
    // check flow state, then decide retry vs stop_flow
}

Prevention

When it happens

Trigger: Any handler error other than the three special-cased ones: internal sendAssistantFlowInput failures, unexpected DB errors during the submit path, serialization of the message chain, etc.

Common situations: Backend-internal bugs in the flow input path; partial DB failures during message insertion; race conditions where the flow state changes between checks; unexpected handler implementations.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/2b26ffe1728a05f7. Report an issue: GitHub.