vxcontrol/pentagi · error
failed to set subtask %d status to failed: %w
Error message
failed to set subtask %d status to failed: %w
What it means
Wraps the error from subtaskWorker.SetStatus when the worker tried to mark a subtask as 'failed' after the agent chain reported PerformResultError. The status write itself failed, so the subtask may remain Running instead of Failed, leaving the flow in an inconsistent state. handleInterrupting resets the subtask to Waiting only when the underlying error is a context interruption.
Source
Thrown at backend/pkg/controller/subtask.go:346
_ = 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) {
if err == nil {
return
}
if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
returnView on GitHub (pinned to ea665308ba)
Solutions
- Inspect the wrapped root error for the DB failure and restore DB connectivity, then reload the flow — LoadSubtasks will pick the subtask up in its persisted state.
- If the cause is context cancellation, the worker already reset the subtask to Waiting; re-run the flow or the subtask.
- Check for concurrent status writers (flow cancellation + worker SetStatus racing) and ensure only the worker mutates subtask status.
- If the subtask is stuck in 'running' in the DB, use the interrupt/reset path or manually reset it to created/waiting before retrying.
Example fix
// before: ignoring the error, leaving subtask stuck running
_ = stw.Run(ctx)
// after: handle and verify state before retrying
if err := stw.Run(ctx); err != nil {
logrus.WithError(err).Error("subtask run failed")
// reload from DB to see actual persisted status before retrying
stc.LoadSubtasks(ctx, taskID, updater)
} Defensive patterns
Strategy: try-catch
Validate before calling
if stw.IsCompleted() { return nil }
if err := db.PingContext(ctx); err != nil { return 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 {
logrus.WithError(err).WithField("subtask_id", id).Error("subtask run failed")
// reload persisted state to learn the true status before any retry
_ = stc.LoadSubtasks(ctx, taskID, updater)
} Prevention
- Always reload subtask status from the DB after a failed run before retrying.
- Keep a single writer for subtask status (the worker) to avoid racing updates.
- Alert on DB errors during status writes — a stuck 'running' subtask blocks the whole flow.
- Provide an operator path to reset stuck subtasks to waiting.
When it happens
Trigger: subtaskWorker.Run() receives providers.PerformResultError from PerformAgentChain and SetStatus(ctx, SubtaskStatusFailed) fails — context canceled during the update, DB unreachable, or the subtask row was concurrently changed.
Common situations: Agent tool execution fails (e.g. Docker container error) at the same moment the user cancels the flow; DB connection pool exhaustion; the task was deleted concurrently; repeated failures during a Postgres failover.
Related errors
- failed to set subtask %d status to finished: %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/0fbd973de2ee30de.
Report an issue: GitHub.