{"record":{"id":"ce768cd1b8f5603e","repo":"vxcontrol/pentagi","slug":"failed-to-delete-subtasks-for-task-d-w","errorCode":null,"errorMessage":"failed to delete subtasks for task %d: %w","messagePattern":"failed to delete subtasks for task (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/subtasks.go","lineNumber":121,"sourceCode":"\tplan, err := stc.taskCtx.Provider.RefineSubtasks(ctx, stc.taskCtx.TaskID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to refine subtasks for task %d: %w\", stc.taskCtx.TaskID, err)\n\t}\n\n\tif len(plan) == 0 {\n\t\treturn nil // no subtasks refined\n\t}\n\n\tsubtaskIDs := make([]int64, 0, len(subtasks))\n\tfor _, subtask := range subtasks {\n\t\tif subtask.Status == database.SubtaskStatusCreated {\n\t\t\tsubtaskIDs = append(subtaskIDs, subtask.ID)\n\t\t}\n\t}\n\n\terr = stc.taskCtx.DB.DeleteSubtasks(ctx, subtaskIDs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete subtasks for task %d: %w\", stc.taskCtx.TaskID, err)\n\t}\n\tstc.InvalidateSubtasks(subtaskIDs)\n\n\t// TODO: change it to insert subtasks in transaction and union it with delete ones\n\tfor _, info := range plan {\n\t\t_, err := stc.taskCtx.DB.CreateSubtask(ctx, database.CreateSubtaskParams{\n\t\t\tStatus:      database.SubtaskStatusCreated,\n\t\t\tTaskID:      stc.taskCtx.TaskID,\n\t\t\tTitle:       info.Title,\n\t\t\tDescription: info.Description,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create subtask for task %d: %w\", stc.taskCtx.TaskID, err)\n\t\t}\n\t}\n\n\treturn nil\n}","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/subtasks.go#L103-L139","documentation":"RefineSubtasks deletes the obsolete subtask IDs in the database before inserting the refined plan. This error wraps a failure of DeleteSubtasks. Because delete and insert are not yet transactional (see the TODO), a failure here leaves the task in the pre-refinement state, which is recoverable by re-running.","triggerScenarios":"DeleteSubtasks fails due to DB connection loss, context cancellation, FK constraint blocking a delete, or an empty/large ID list hitting query limits.","commonSituations":"Postgres connection pool exhausted during concurrent flows; long-running refine transaction timing out; DB read replica used for writes by misconfiguration.","solutions":["Check the wrapped DB error in logs for constraint/connection details","Retry RefineSubtasks — deletes happen before inserts so no partial plan exists","Verify FK constraints on subtasks table (dependent rows must be deleted first)","Run delete+insert inside a single transaction to make refinement atomic"],"exampleFix":"// before\nerr = stc.taskCtx.DB.DeleteSubtasks(ctx, subtaskIDs)\nif err != nil {\n    return fmt.Errorf(\"failed to delete subtasks for task %d: %w\", stc.taskCtx.TaskID, err)\n}\n// after\nif len(subtaskIDs) > 0 {\n    err = stc.taskCtx.DB.DeleteSubtasks(ctx, subtaskIDs)\n    if err != nil {\n        return fmt.Errorf(\"failed to delete subtasks for task %d: %w\", stc.taskCtx.TaskID, err)\n    }\n}","handlingStrategy":"try-catch","validationCode":"if len(subtaskIDs) == 0 { /* skip delete */ }","typeGuard":null,"tryCatchPattern":"if err := stc.taskCtx.DB.DeleteSubtasks(ctx, subtaskIDs); err != nil {\n    var pqErr *pq.Error\n    if errors.As(err, &pqErr) { log.Error(\"delete failed\", \"constraint\", pqErr.Constraint) }\n    return fmt.Errorf(\"failed to delete subtasks for task %d: %w\", taskID, err)\n}","preventionTips":["Wrap delete+insert in one transaction (resolve the code TODO)","Check FK constraints on subtask-dependent tables","Verify no concurrent refinement of the same task"],"tags":["database","delete","transaction"],"backgroundTag":"database-write-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}