vxcontrol/pentagi · error
failed to update subtask %d status to created: %w
Error message
failed to update subtask %d status to created: %w
What it means
LoadSubtaskWorker resets a subtask stuck in a non-Created state (e.g. 'processing' after a crash) back to SubtaskStatusCreated via UpdateSubtaskStatus. This error wraps a failure of that status-reset UPDATE, identified by subtask ID. It indicates the resume/recovery path could not normalize the subtask state.
Source
Thrown at backend/pkg/controller/subtask.go:104
ctx, span := obs.Observer.NewSpan(ctx, obs.SpanKindInternal, "controller.LoadSubtaskWorker")
defer span.End()
var completed, waiting bool
switch subtask.Status {
case database.SubtaskStatusFinished, database.SubtaskStatusFailed:
completed = true
case database.SubtaskStatusWaiting:
waiting = true
case database.SubtaskStatusRunning:
var err error
// if subtask is running, it means that it was not finished by previous run
// so we need to set it to created and continue from the beginning
subtask, err = taskCtx.DB.UpdateSubtaskStatus(ctx, database.UpdateSubtaskStatusParams{
Status: database.SubtaskStatusCreated,
ID: subtask.ID,
})
if err != nil {
return nil, fmt.Errorf("failed to update subtask %d status to created: %w", subtask.ID, err)
}
case database.SubtaskStatusCreated:
return nil, fmt.Errorf("subtask %d has created yet: %w", subtask.ID, ErrNothingToLoad)
default:
return nil, fmt.Errorf("unexpected subtask status: %s", subtask.Status)
}
msgChains, err := taskCtx.DB.GetSubtaskPrimaryMsgChains(ctx, database.Int64ToNullInt64(&subtask.ID))
if err != nil {
return nil, fmt.Errorf("failed to get subtask primary msg chains for subtask %d: %w", subtask.ID, err)
}
if len(msgChains) == 0 {
return nil, fmt.Errorf("subtask %d has no msg chains: %w", subtask.ID, ErrNothingToLoad)
}
return &subtaskWorker{
mx: &sync.RWMutex{},View on GitHub (pinned to ea665308ba)
Solutions
- Check DB connectivity and retry LoadSubtasks once the database is reachable.
- Inspect the wrapped cause for lock timeouts (deadlocks/row locks) and reduce concurrent reload of the same subtask.
- Verify the subtask row still exists; if deleted, remove it from the load queue instead of retrying.
- Ensure all goose migrations ran so status enums/columns match the code's expectations.
Example fix
// before
workers, err := LoadSubtasks(ctx, taskCtx)
if err != nil {
return err
}
// after
workers, err := LoadSubtasks(ctx, taskCtx)
if err != nil {
if isRetryableDBError(err) {
time.Sleep(backoff)
workers, err = LoadSubtasks(ctx, taskCtx)
}
if err != nil {
return fmt.Errorf("load subtasks after restart: %w", err)
}
} Defensive patterns
Strategy: retry
Validate before calling
// before recovery load, confirm the row is updatable and DB reachable
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("db unavailable: %w", err)
}
var st string
err := db.QueryRowContext(ctx, `SELECT status FROM subtasks WHERE id=$1`, id).Scan(&st)
if err != nil { return err } Type guard
func IsStatusResetFailure(err error) bool {
return strings.Contains(err.Error(), "status to created")
} Try / catch
worker, err := LoadSubtaskWorker(ctx, taskCtx, subtask)
if err != nil {
if isTransientDBError(err) {
return retryWithBackoff(ctx, func() error {
_, err = LoadSubtaskWorker(ctx, taskCtx, subtask)
return err
})
}
return err
} Prevention
- Run recovery loads only after the DB connection pool is healthy.
- Avoid concurrent recovery of the same subtask; use a single recovery goroutine or lease.
- Tune lock_timeout/statement_timeout for status UPDATEs.
- Apply all goose migrations before starting recovery.
When it happens
Trigger: Calling LoadSubtasks after restart for a subtask whose status was e.g. 'processing' when the DB UPDATE fails — DB down, row locked, row deleted concurrently, or constraint violation.
Common situations: Server crash left subtasks in 'processing'; on recovery the database is temporarily unavailable; concurrent workers race to reload the same subtask causing lock contention; migrations not applied so the status column value differs.
Related errors
- failed to get subtask primary msg chains for subtask %d: %w
- failed to set subtask %d status: %w
- failed to set subtask %d status to finished: %w
- failed to set subtask %d status to failed: %w
- failed to get subtasks for task %d: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/5aec13eaa1a66712.
Report an issue: GitHub.