{"record":{"id":"6d843a404d1f67a4","repo":"vxcontrol/pentagi","slug":"failed-to-set-subtask-d-status-w","errorCode":null,"errorMessage":"failed to set subtask %d status: %w","messagePattern":"failed to set subtask (.+?) status: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/subtask.go","lineNumber":209,"sourceCode":"\t})\n\tif err != nil {\n\t\tif errors.Is(err, sql.ErrNoRows) {\n\t\t\t// Replacement can delete the row before this stale worker finishes.\n\t\t\t// Treat it as complete to keep task shutdown idempotent.\n\t\t\tlogrus.WithContext(ctx).WithFields(logrus.Fields{\n\t\t\t\t\"subtask_id\":       stw.subtaskCtx.SubtaskID,\n\t\t\t\t\"requested_status\": status,\n\t\t\t}).Warn(\"subtask no longer exists in the database, treating as already finished\")\n\n\t\t\tstw.mx.Lock()\n\t\t\tstw.completed = true\n\t\t\tstw.waiting = false\n\t\t\tstw.mx.Unlock()\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"failed to set subtask %d status: %w\", stw.subtaskCtx.SubtaskID, err)\n\t}\n\n\tstw.mx.Lock()\n\tdefer stw.mx.Unlock()\n\n\tswitch status {\n\tcase database.SubtaskStatusRunning:\n\t\tstw.completed = false\n\t\tstw.waiting = false\n\t\terr = stw.updater.SetStatus(ctx, database.TaskStatusRunning)\n\tcase database.SubtaskStatusWaiting:\n\t\tstw.completed = false\n\t\tstw.waiting = true\n\t\terr = stw.updater.SetStatus(ctx, database.TaskStatusWaiting)\n\tcase database.SubtaskStatusFinished, database.SubtaskStatusFailed:\n\t\tstw.completed = true\n\t\tstw.waiting = false\n\t\t// statuses Finished and Failed will be produced by stack from Run function call","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/subtask.go#L191-L227","documentation":"SetStatus persists a new status for the subtask via the database before applying in-memory worker state; this error wraps a failure of that status-update call. Callers are Run, handleInterrupting, and Finish — i.e. every lifecycle transition of the subtask goes through here, so a DB problem blocks the whole subtask lifecycle.","triggerScenarios":"Any lifecycle transition (run, interrupt, finish) when the underlying UPDATE fails: DB down, row locked by a concurrent writer, transaction timeout, or the subtask row was deleted mid-run.","commonSituations":"Postgres failover or connection-pool exhaustion during a long-running subtask; two workers controlling the same subtask causing lock waits; migrations/schema drift; the flow was deleted while its subtask was still running.","solutions":["Inspect the wrapped DB error; if transient (connection/lock timeout), retry the status transition.","Ensure only one worker instance controls a given subtask (see error 141's flow-worker map) to avoid lock contention.","Verify DB health, pool sizing, and lock_timeout settings for long transactions.","Check that the subtask row still exists; if the parent flow was removed, abort the worker cleanly."],"exampleFix":"// before\nif err := stw.SetStatus(ctx, database.SubtaskStatusFinished); err != nil {\n    return err\n}\n// after\nif err := stw.SetStatus(ctx, database.SubtaskStatusFinished); err != nil {\n    if isTransientDBError(err) {\n        return retry(ctx, 3, backoff, func() error {\n            return stw.SetStatus(ctx, database.SubtaskStatusFinished)\n        })\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// pre-check DB reachability before lifecycle transitions\nif err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"db unavailable, deferring status change: %w\", err)\n}","typeGuard":"func IsStatusUpdateFailure(err error) bool {\n    return strings.Contains(err.Error(), \"failed to set subtask\")\n}","tryCatchPattern":"if err := stw.SetStatus(ctx, database.SubtaskStatusFinished); err != nil {\n    if isTransientDBError(err) {\n        return retry(ctx, 3, backoff, func() error {\n            return stw.SetStatus(ctx, database.SubtaskStatusFinished)\n        })\n    }\n    log.Error(\"status update failed permanently\", \"subtask\", stw.SubtaskID, \"err\", err)\n    return err\n}","preventionTips":["Ensure single-ownership: one worker per subtask, guarded by the flow's worker map.","Tune DB lock/statement timeouts for status UPDATEs.","Monitor for rows locked by long transactions during flow deletion.","Retry only transient DB errors; surface permanent ones to operators."],"tags":["database","status-update","subtask","locking"],"backgroundTag":"database-update-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}