vxcontrol/pentagi · error

task_id must be a positive integer

Error message

task_id must be a positive integer

What it means

patch_flow_subtasks requires a positive integer task_id; the parsed action had task_id <= 0 (missing or non-positive). This is an argument-validation guard executed after JSON parsing succeeds but before any database access.

Source

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

	handler func(ctx context.Context, taskID int64, patch SubtaskPatch) error
}

func NewPatchFlowSubtasksTool(
	flowID int64,
	db database.Querier,
	handler func(ctx context.Context, taskID int64, patch SubtaskPatch) error,
) *patchFlowSubtasksTool {
	return &patchFlowSubtasksTool{flowID: flowID, db: db, handler: handler}
}

func (t *patchFlowSubtasksTool) Handle(ctx context.Context, name string, args json.RawMessage) (string, error) {
	var action PatchFlowSubtasksAction
	if err := json.Unmarshal(args, &action); err != nil {
		return "", fmt.Errorf("failed to parse patch_flow_subtasks args: %w", err)
	}

	if action.TaskID <= 0 {
		return "", fmt.Errorf("task_id must be a positive integer")
	}

	// Validate flow is not running
	tasks, err := t.db.GetFlowTasks(ctx, t.flowID)
	if err != nil {
		return "", fmt.Errorf("failed to check flow status: %w", err)
	}

	for _, task := range tasks {
		if task.Status == database.TaskStatusRunning {
			return "", stateGuard(fmt.Errorf(
				"task %q (ID: %d) is currently running; "+
					"patching is not allowed while a task is executing. "+
					"Call %s first, then retry %s",
				task.Title, task.ID, StopFlowToolName, PatchFlowSubtasksToolName))
		}
	}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Call get_flow_status with detail='tasks' to obtain valid task IDs.
  2. Resend patch_flow_subtasks with the real positive task_id.
  3. If the LLM keeps guessing, include the task list in its context before the patch call.

Example fix

// before
{"task_id": 0, "operations": [...]}
// after: fetch IDs first, then
{"task_id": 17, "operations": [...]}
Defensive patterns

Strategy: validation

Validate before calling

if taskID <= 0 {
    return errors.New("refusing to patch: fetch a valid task_id via get_flow_status detail='tasks' first")
}

Type guard

func hasValidTaskID(args json.RawMessage) bool {
    var a struct { TaskID int64 `json:"task_id"` }
    if json.Unmarshal(args, &a) != nil { return false }
    return a.TaskID > 0
}

Try / catch

if _, err := tool.Handle(ctx, "patch_flow_subtasks", args); err != nil &&
    strings.Contains(err.Error(), "task_id must be a positive integer") {
    // refresh known task IDs and rebuild args
    args = buildArgsFromStatus(getFlowStatus(ctx))
}

Prevention

When it happens

Trigger: Calling patch_flow_subtasks with task_id omitted (defaults to 0) or explicitly 0/negative — typically when the LLM doesn't know the real task ID and emits a placeholder.

Common situations: LLM guessing a task_id because it never fetched the plan; template calls left with default values; client code passing an unset int64 field.

Understand the failure class

Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.

Related errors


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