vxcontrol/pentagi · error

failed to parse patch_flow_subtasks args: %w

Error message

failed to parse patch_flow_subtasks args: %w

What it means

patch_flow_subtasks received arguments that could not be unmarshalled into PatchFlowSubtasksAction, so the tool rejects the call before touching the database. The JSON structure/types of the arguments do not match the action schema (e.g. task_id is a string, operations is not an array, malformed JSON).

Source

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

// patchFlowSubtasksTool implements patch_flow_subtasks.
type patchFlowSubtasksTool struct {
	flowID  int64
	db      database.Querier
	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",

View on GitHub (pinned to ea665308ba)

Solutions

  1. Read the wrapped error (%w) to see the exact unmarshal failure (field and type).
  2. Resend with valid JSON: {"task_id": <int>, "operations": [...]}.
  3. Ensure task_id is a JSON number, not a quoted string.
  4. If an LLM produced the args, regenerate with the current tool schema; update stale prompt definitions.

Example fix

// before
{"task_id": "42", "operations": [{"op": "remove", "index": 0}]}
// after
{"task_id": 42, "operations": [{"op": "remove", "index": 0}]}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the payload shape before invoking the tool
raw, _ := json.Marshal(args)
var probe struct {
    TaskID     *int64           `json:"task_id"`
    Operations []map[string]any `json:"operations"`
}
if err := json.Unmarshal(raw, &probe); err != nil || probe.TaskID == nil {
    return errors.New("invalid patch_flow_subtasks args: task_id must be a JSON number")
}

Type guard

func validPatchArgs(args json.RawMessage) bool {
    var a struct {
        TaskID     int64   `json:"task_id"`
        Operations []any   `json:"operations"`
    }
    return json.Unmarshal(args, &a) == nil && a.TaskID > 0 && a.Operations != nil
}

Try / catch

if _, err := tool.Handle(ctx, "patch_flow_subtasks", args); err != nil {
    var uErr *json.UnmarshalTypeError
    if errors.As(err, &uErr) {
        log.Printf("bad args field %s: expected %s", uErr.Field, uErr.Type)
    }
}

Prevention

When it happens

Trigger: The LLM or caller emits patch_flow_subtasks args with invalid JSON or wrong field types: task_id as a string instead of number, missing required shape of operations, trailing garbage, or double-encoded JSON strings.

Common situations: LLM hallucinating a different schema for the tool; hand-crafted API calls with wrong payload shape; older prompt/tool definitions after a schema change; JSON strings quoted one level too many.

Understand the failure class

Related errors


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