vxcontrol/pentagi · error
failed to create subtask for task %d: %w
Error message
failed to create subtask for task %d: %w
What it means
Wraps the error from DB.CreateSubtask while persisting each subtask from a generated plan. The plan was produced successfully but writing a subtask row to PostgreSQL failed, aborting generation partway (creation is not transactional — see the TODO in the source). Some subtasks may already have been created, so the task can be left with a partial plan.
Source
Thrown at backend/pkg/controller/subtasks.go:90
plan, err := stc.taskCtx.Provider.GenerateSubtasks(ctx, stc.taskCtx.TaskID)
if err != nil {
return fmt.Errorf("failed to generate subtasks for task %d: %w", stc.taskCtx.TaskID, err)
}
if len(plan) == 0 {
return fmt.Errorf("no subtasks generated for task %d", stc.taskCtx.TaskID)
}
// TODO: change it to insert subtasks in transaction
for _, info := range plan {
_, err := stc.taskCtx.DB.CreateSubtask(ctx, database.CreateSubtaskParams{
Status: database.SubtaskStatusCreated,
TaskID: stc.taskCtx.TaskID,
Title: info.Title,
Description: info.Description,
})
if err != nil {
return fmt.Errorf("failed to create subtask for task %d: %w", stc.taskCtx.TaskID, err)
}
}
return nil
}
func (stc *subtaskController) RefineSubtasks(ctx context.Context) error {
subtasks, err := stc.taskCtx.DB.GetTaskSubtasks(ctx, stc.taskCtx.TaskID)
if err != nil {
return fmt.Errorf("failed to get task %d subtasks: %w", stc.taskCtx.TaskID, err)
}
plan, err := stc.taskCtx.Provider.RefineSubtasks(ctx, stc.taskCtx.TaskID)
if err != nil {
return fmt.Errorf("failed to refine subtasks for task %d: %w", stc.taskCtx.TaskID, err)
}
if len(plan) == 0 {View on GitHub (pinned to ea665308ba)
Solutions
- Inspect the wrapped error; if transient (connection/context), retry GenerateSubtasks — but first check for a partial plan already in the DB to avoid duplicates.
- Check errors.Is(err, context.Canceled): the caller canceled during insertion; the partially created subtasks remain and can be loaded with LoadSubtasks.
- Verify the subtasks schema is up to date (goose migrations) so CreateSubtaskParams matches the table.
- If duplicates from partial inserts are the issue, delete the task's subtasks before regenerating.
- Contribute/apply the transactional insert (the TODO) so plan creation is all-or-nothing.
Example fix
// before: partial inserts possible
for _, info := range plan {
_, err := stc.taskCtx.DB.CreateSubtask(ctx, params)
if err != nil {
return fmt.Errorf("failed to create subtask for task %d: %w", taskID, err)
}
}
// after: check for existing partial plan before regenerating
existing, _ := stc.taskCtx.DB.GetTaskSubtasks(ctx, taskID)
if len(existing) > 0 {
return nil // plan partially created; resume instead of duplicating
} Defensive patterns
Strategy: try-catch
Validate before calling
if ctx.Err() != nil { return ctx.Err() }
if err := db.PingContext(ctx); err != nil { return err }
// avoid duplicating a partial plan
existing, _ := db.GetTaskSubtasks(ctx, taskID)
if len(existing) > 0 { return ErrPlanExists } Type guard
func isTransientInsertError(err error) bool {
var pgErr *pgconn.PgError
return errors.As(err, &pgErr) &&
(pgErr.Code == "08000" || pgErr.Code == "08006" || pgErr.Code == "40001")
} Try / catch
if err := stc.GenerateSubtasks(ctx); err != nil {
if strings.Contains(err.Error(), "failed to create subtask") {
// partial plan may exist: inspect DB and clean up or resume
logrus.WithError(err).WithField("task_id", taskID).Error("partial subtask insert")
return stc.reconcilePartialPlan(ctx, taskID)
}
return err
} Prevention
- Check for existing subtasks before regenerating a plan to avoid duplicates from partial inserts.
- Keep DB connections healthy — monitor pool saturation during plan generation.
- Make subtask insertion transactional (all plan rows or none) to eliminate partial plans.
- Run migrations so CreateSubtaskParams always matches the table schema.
When it happens
Trigger: In GenerateSubtasks' loop, stc.taskCtx.DB.CreateSubtask(ctx, CreateSubtaskParams{...}) fails for one of the plan entries — DB connection loss, context cancellation mid-loop, unique constraint violation, or schema mismatch.
Common situations: DB restart or connection pool exhaustion mid-loop; the caller's context canceled halfway through inserting the plan; migration drift making CreateSubtaskParams incompatible with the table; long plans hitting a statement timeout.
Related errors
- failed to get subtasks for task %d: %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 set subtask %d result: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/cd89bcd0000f79e0.
Report an issue: GitHub.