vxcontrol/pentagi · error
failed to set subtask %d status to finished: %w
Error message
failed to set subtask %d status to finished: %w
What it means
Wraps the error returned by subtaskWorker.SetStatus when the worker tried to transition a subtask to 'finished' after the agent chain reported PerformResultDone. The database status update failed (likely context cancellation, DB connectivity loss, or a status conflict), so the subtask is left in a non-finished state even though the work succeeded. handleInterrupting is invoked first, so context.Canceled/DeadlineExceeded resets the subtask to Waiting for a later retry.
Source
Thrown at backend/pkg/controller/subtask.go:341
}
errChainConsistency := stw.subtaskCtx.Provider.EnsureChainConsistency(ctx, msgChainID)
if errChainConsistency != nil {
err = errors.Join(err, errChainConsistency)
}
_ = stw.SetStatus(ctx, database.SubtaskStatusWaiting)
return fmt.Errorf("failed to perform agent chain for subtask %d: %w", subtaskID, err)
}
switch performResult {
case providers.PerformResultWaiting:
if err := stw.SetStatus(ctx, database.SubtaskStatusWaiting); err != nil {
stw.handleInterrupting(err)
return err
}
case providers.PerformResultDone:
if err := stw.SetStatus(ctx, database.SubtaskStatusFinished); err != nil {
stw.handleInterrupting(err)
return fmt.Errorf("failed to set subtask %d status to finished: %w", subtaskID, err)
}
case providers.PerformResultError:
if err := stw.SetStatus(ctx, database.SubtaskStatusFailed); err != nil {
stw.handleInterrupting(err)
return fmt.Errorf("failed to set subtask %d status to failed: %w", subtaskID, err)
}
default:
return fmt.Errorf("unknown perform result: %d", performResult)
}
return nil
}
// handleInterrupting sets this subtask (and task/flow via SetStatus back-propagation)
// to Waiting when err is context.Canceled or context.DeadlineExceeded. Use after the subtask
// was advanced past Waiting (e.g. Running) but the run aborts before PerformAgentChain's
// normal error handler, or when a late SetStatus fails with a context interruption.
func (stw *subtaskWorker) handleInterrupting(err error) {View on GitHub (pinned to ea665308ba)
Solutions
- Check DB connectivity/pool health (pgx logs) and retry the flow; if the error is context.Canceled the worker already reset the subtask to Waiting, so re-run it.
- Ensure the context passed to Run is not canceled before completion — don't abort the flow goroutine while subtasks are finishing.
- Verify no concurrent code path updates the same subtask status (idempotency: finished→finished transitions or unique constraints failing).
- Check the wrapped error (%w) in logs for the root cause (e.g. SQLSTATE) and address that specifically.
Example fix
// before: run with the flow's context that gets canceled on timeout
err := stw.Run(flowCtx)
// after: tolerate interruptions — worker resets to Waiting; re-dispatch
if err != nil {
var subtaskErr *controller.SubtaskError
if errors.Is(err, context.Canceled) {
// subtask was reset to Waiting by handleInterrupting; safe to retry
stc.TryRequeueSubtask(subtaskID)
}
} Defensive patterns
Strategy: retry
Validate before calling
if stw.IsCompleted() { return nil } // never run a terminal subtask
if err := db.PingContext(ctx); err != nil { return fmt.Errorf("db unavailable: %w", err) } Type guard
func isInterrupting(err error) bool {
return errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)
} Try / catch
if err := stw.Run(ctx); err != nil {
if isInterrupting(err) {
// worker reset subtask to Waiting; safe to requeue
requeue(subtaskID)
return nil
}
return fmt.Errorf("run failed: %w", err)
} Prevention
- Don't cancel the flow context while subtasks are transitioning to a terminal state.
- Monitor PostgreSQL connection-pool health before dispatching long flows.
- Use errors.Is for context.Canceled to distinguish retryable interruptions from hard failures.
- Make status transitions idempotent at the DB layer (ON CONFLICT DO NOTHING on same-status updates).
When it happens
Trigger: subtaskWorker.Run() gets providers.PerformResultDone from Provider.PerformAgentChain and the subsequent SetStatus(ctx, SubtaskStatusFinished) returns an error — e.g. the run context was canceled mid-update, the PostgreSQL connection dropped, or the row was concurrently modified.
Common situations: Flow cancellation or shutdown racing with task completion; DB pod restart/connection pool exhaustion in Kubernetes; pgx 'conn busy' or serialization failures under heavy concurrent flow updates; the parent task being deleted while its last subtask finishes.
Related errors
- failed to set subtask %d status to failed: %w
- failed to update subtask %d status to created: %w
- failed to get subtask primary msg chains for subtask %d: %w
- failed to set subtask %d status: %w
- failed to get subtasks for task %d: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/fa14e352922adefb.
Report an issue: GitHub.