vxcontrol/pentagi · error

failed to check subtask state for task %d: %w

Error message

failed to check subtask state for task %d: %w

What it means

This error wraps a failure of t.db.GetFlowSubtasks for the flow while Handle was checking whether any existing subtasks belong to the task, because no planned subtasks were found but the action carried operations. It is a defensive consistency check: the agent wants to patch/create subtasks but the DB state could not be verified. The wrapped cause carries the real DB error.

Source

Thrown at backend/pkg/tools/flow_manager.go:885

			break
		}
	}
	if !taskBelongsToFlow {
		return "", stateGuard(fmt.Errorf(
			"task ID %d was not found in this flow; "+
				"obtain a valid task ID from %s with detail='tasks'",
			action.TaskID, GetFlowStatusToolName))
	}

	planned, err := t.db.GetTaskPlannedSubtasks(ctx, action.TaskID)
	if err != nil {
		return "", fmt.Errorf("failed to get planned subtasks for task %d: %w", action.TaskID, err)
	}

	if len(planned) == 0 && len(action.Operations) > 0 {
		subtasks, err := t.db.GetFlowSubtasks(ctx, t.flowID)
		if err != nil {
			return "", fmt.Errorf("failed to check subtask state for task %d: %w", action.TaskID, err)
		}

		for _, st := range subtasks {
			if st.TaskID != action.TaskID {
				continue
			}
			switch st.Status {
			case database.SubtaskStatusWaiting:
				return "", stateGuard(fmt.Errorf(
					"task %d has a subtask (ID: %d, %q) waiting for user input. "+
						"Only 'created' subtasks can be patched, but you can include the waiting subtask's ID in your operations to modify or remove it. "+
						"Alternatively, answer it via %s first",
					action.TaskID, st.ID, st.Title, SubmitFlowInputToolName))
			case database.SubtaskStatusRunning:
				return "", stateGuard(fmt.Errorf(
					"task %d has a subtask (ID: %d, %q) currently running. "+
						"Call %s first, then retry",
					action.TaskID, st.ID, st.Title, StopFlowToolName))

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the wrapped DB error in logs to find the root cause
  2. Verify PostgreSQL is reachable and the connection pool is not exhausted
  3. Retry the action once connectivity is restored
  4. Ensure goose migrations completed so the subtasks table is queryable

Example fix

// before
subtasks, err := t.db.GetFlowSubtasks(ctx, t.flowID)
if err != nil {
	return "", fmt.Errorf("failed to check subtask state for task %d: %w", action.TaskID, err)
}
// after
subtasks, err := t.db.GetFlowSubtasks(ctx, t.flowID)
if err != nil {
	if ctx.Err() != nil {
		return "", fmt.Errorf("flow context cancelled while checking subtask state for task %d: %w", action.TaskID, ctx.Err())
	}
	return "", fmt.Errorf("failed to check subtask state for task %d: %w", action.TaskID, err)
}
Defensive patterns

Strategy: retry

Validate before calling

// preflight: ensure flow context and DB are alive before invoking the tool
if err := db.PingContext(ctx); err != nil {
	return fmt.Errorf("database unreachable: %w", err)
}

Try / catch

subtasks, err := mgr.Handle(ctx, action)
if err != nil && strings.Contains(err.Error(), "failed to check subtask state") {
	if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
		// re-invoke with a fresh context
	}
}

Prevention

When it happens

Trigger: Create/patch-subtasks action with len(action.Operations) > 0 and zero planned subtasks, and GetFlowSubtasks(ctx, t.flowID) returns a DB error (connection failure, timeout, cancelled context).

Common situations: Database under heavy load during large flows; ctx cancelled by an upstream deadline; replica/failover hiccup in PostgreSQL; misconfigured DSN after an environment change.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/054c6620a7bb9783. Report an issue: GitHub.