vxcontrol/pentagi · error
failed to stop flow: %w
Error message
failed to stop flow: %w
What it means
stop_flow invoked the flow-stop handler and it returned an error that is neither DeadlineExceeded nor Canceled. The raw error is wrapped, preserving the underlying reason (handler failure, internal error, store failure). The flow may or may not have been stopped.
Source
Thrown at backend/pkg/tools/flow_manager.go:650
break
}
}
if !isRunning {
return "No running task found — the flow is already in 'waiting' state and ready to accept input.", nil
}
stopCtx, stopCancel := context.WithTimeout(ctx, flowOperationTimeout)
defer stopCancel()
if err := t.handler(stopCtx, action.Reason); err != nil {
if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
return "", fmt.Errorf(
"stop timed out after %s — the task may still be winding down. "+
"Call %s to check the current state before proceeding",
flowOperationTimeout, GetFlowStatusToolName)
}
return "", fmt.Errorf("failed to stop flow: %w", err)
}
// Re-query task statuses to report the actual state the flow reached.
newTasks, err := t.db.GetFlowTasks(ctx, t.flowID)
if err != nil {
// Stop succeeded but we cannot verify the new state — return a safe partial message.
return fmt.Sprintf(
"Flow stop initiated (reason: %s). Could not verify new status: %s. "+
"Call %s to confirm before proceeding.",
action.Reason, err, GetFlowStatusToolName), nil
}
for _, task := range newTasks {
if task.Status == database.TaskStatusRunning {
return fmt.Sprintf(
"Stop requested (reason: %s), but a task is still running — the flow has not reached 'waiting' yet. "+
"Call %s to confirm before making further changes.",
action.Reason, GetFlowStatusToolName), nilView on GitHub (pinned to ea665308ba)
Solutions
- Read the wrapped cause (%v / errors.Is) to identify the handler failure.
- Call get_flow_status to determine the flow's actual state before attempting anything else.
- Retry stop_flow once transient conditions clear.
- If persistent, capture backend logs and restart the pentagi service; report if reproducible.
Example fix
// verify actual state after failed stop
status, _ := getFlowStatus(flowId)
if status == 'running' {
// retry stop_flow
} Defensive patterns
Strategy: try-catch
Try / catch
try {
await tool.call('stop_flow', { reason: 'stop requested' });
} catch (err) {
if (String(err).includes('failed to stop flow') && !String(err).includes('timed out')) {
log.error('stop handler failed', parseWrappedCause(err));
// verify state and retry
const status = await tool.call('get_flow_status', { detail: 'summary' });
}
} Prevention
- Inspect the wrapped cause before retrying blindly
- Check flow status after every failed stop
- Watch backend logs for recurring handler failures
- Restart the backend if stop handlers persistently fail
When it happens
Trigger: Calling stop_flow when the injected stop handler fails for a non-context reason — e.g. an internal error while signalling cancellation to the flow's goroutines, or a store error during the stop path.
Common situations: Backend-internal failure while propagating cancellation; race with flow lifecycle transitions; bugs or resource exhaustion (goroutines, DB pool) inside the stop handler.
Related errors
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/79e89642a11ae9a4.
Report an issue: GitHub.