{"record":{"id":"5943ac3f4f2c2651","repo":"vxcontrol/pentagi","slug":"failed-to-get-subtasks-for-task-d-w","errorCode":null,"errorMessage":"failed to get subtasks for task %d: %w","messagePattern":"failed to get subtasks for task (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/subtasks.go","lineNumber":48,"sourceCode":"\ttaskCtx  *TaskContext\n\tsubtasks map[int64]SubtaskWorker\n}\n\nfunc NewSubtaskController(taskCtx *TaskContext) SubtaskController {\n\treturn &subtaskController{\n\t\tmx:       &sync.Mutex{},\n\t\ttaskCtx:  taskCtx,\n\t\tsubtasks: make(map[int64]SubtaskWorker),\n\t}\n}\n\nfunc (stc *subtaskController) LoadSubtasks(ctx context.Context, taskID int64, updater TaskUpdater) error {\n\tstc.mx.Lock()\n\tdefer stc.mx.Unlock()\n\n\tsubtasks, err := stc.taskCtx.DB.GetTaskSubtasks(ctx, taskID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get subtasks for task %d: %w\", taskID, err)\n\t}\n\n\tif len(subtasks) == 0 {\n\t\treturn fmt.Errorf(\"no subtasks found for task %d: %w\", taskID, ErrNothingToLoad)\n\t}\n\n\tfor _, subtask := range subtasks {\n\t\tst, err := LoadSubtaskWorker(ctx, subtask, stc.taskCtx, updater)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, ErrNothingToLoad) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to create subtask worker: %w\", err)\n\t\t}\n\n\t\tstc.subtasks[subtask.ID] = st\n\t}","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/subtasks.go#L30-L66","documentation":"Wraps the error from DB.GetTaskSubtasks when loading all persisted subtask workers for a task into the subtaskController. Failure means the in-memory flow workers could not be restored — usually a database connectivity/query error. The taskID is included to help locate the offending task.","triggerScenarios":"subtaskController.LoadSubtasks(ctx, taskID, updater) calls stc.taskCtx.DB.GetTaskSubtasks(ctx, taskID) and the SQLC query returns an error — connection failure, canceled context, or a schema mismatch.","commonSituations":"Postgres down or restarting when a server restart tries to resume flows; pgvector/DB migration not applied so the subtasks query fails; taskID referencing a task deleted concurrently between existence check and load; network partition between backend and DB.","solutions":["Restore PostgreSQL connectivity and retry LoadSubtasks (flows are resumable — nothing is lost).","Check the wrapped error for SQLSTATE/context errors; if context.Canceled, the caller canceled too early.","Verify migrations ran (goose) — an outdated subtasks schema breaks GetTaskSubtasks.","Confirm the taskID is valid and the task row still exists at load time."],"exampleFix":"// before: retrying immediately in a tight loop\nfor {\n    if err := stc.LoadSubtasks(ctx, taskID, updater); err == nil { break }\n}\n// after: backoff + root-cause log\nif err := stc.LoadSubtasks(ctx, taskID, updater); err != nil {\n    logrus.WithError(err).WithField(\"task_id\", taskID).Error(\"load failed\")\n    time.Sleep(backoff)\n    return\n}","handlingStrategy":"retry","validationCode":"if err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"database unreachable, cannot load task %d\", taskID)\n}\n// taskID must be positive\nif taskID <= 0 { return ErrInvalidTaskID }","typeGuard":"func isDBError(err error) bool {\n    var pgErr *pgconn.PgError\n    return errors.As(err, &pgErr) || errors.Is(err, context.Canceled)\n}","tryCatchPattern":"err := stc.LoadSubtasks(ctx, taskID, updater)\nif err != nil {\n    if isDBError(err) {\n        // transient: backoff and retry\n        time.Sleep(2 * time.Second)\n        return stc.LoadSubtasks(ctx, taskID, updater)\n    }\n    return err\n}","preventionTips":["Verify DB health (ping/migrations) at startup before accepting flow-resume requests.","Run all goose migrations before the server starts serving.","Wrap DB reads in retry with backoff for transient connection errors.","Log the wrapped root error with taskID for fast diagnosis."],"tags":["database","sqlc","subtask","persistence"],"backgroundTag":"database-query-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}