go-task/task · error

matrix reference %q must resolve to a list

Error message

matrix reference %q must resolve to a list

What it means

resolveMatrixRefs in variables.go resolves `for`-loop matrix references via templater.ResolveRef and expects the result to be a list. If the referenced variable resolves to something that is not a list (scalar, map, empty), the library throws this error because a matrix iteration source must be a list. The reference string is included to point at the offending matrix entry.

Source

Thrown at variables.go:497

	for _, row := range matrix.All() {
		if row.Ref != "" {
			hasRef = true
			break
		}
	}
	if !hasRef {
		return matrix, nil
	}
	resolved := matrix.DeepCopy()
	for _, row := range resolved.All() {
		if row.Ref != "" {
			v := templater.ResolveRef(row.Ref, cache)
			if cache.Err() != nil {
				return nil, cache.Err()
			}
			value, ok := resolvedAsAnySlice(v)
			if !ok {
				return nil, fmt.Errorf("matrix reference %q must resolve to a list", row.Ref)
			}
			row.Value = value
		}
	}
	return resolved, nil
}

func resolveEnumRefs(requires *ast.Requires, cache *templater.Cache) error {
	if requires == nil || len(requires.Vars) == 0 {
		return nil
	}
	for _, v := range requires.Vars {
		if v.Enum == nil || v.Enum.Ref == "" {
			continue
		}
		resolved := templater.ResolveRef(v.Enum.Ref, cache)
		if cache.Err() != nil {
			return cache.Err()

View on GitHub (pinned to 385e5ad92a)

Solutions

  1. Inspect the referenced variable and change its definition to a list (YAML sequence or JSON array).
  2. If it is a dynamic variable, make the command output a JSON array of values.
  3. Correct the matrix ref in the `for` section so it points at the list variable you intended.
  4. Add a test (like TestResolveMatrixRefsDoesNotMutateInput) or validation step that asserts the variable's type before running.

Example fix

// before
vars:
  TARGETS: prod
for:
  matrix: [{ref: .TARGETS}]
// after
vars:
  TARGETS: [dev, prod]
for:
  matrix: [{ref: .TARGETS}]
Defensive patterns

Strategy: validation

Validate before calling

func mustBeList(name string, v any) error {
    switch t := v.(type) {
    case []any:
        if len(t) == 0 { return fmt.Errorf("%s is empty", name) }
        return nil
    default:
        return fmt.Errorf("%s must be a list, got %T", name, v)
    }
}

Try / catch

values, err := resolveMatrixRefs(...)
if err != nil {
    var target any
    if strings.Contains(err.Error(), "must resolve to a list") {
        return fmt.Errorf("check your matrix ref variable type: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: A task's `for` loop uses `matrix: [{ref: .VAR}]` (or similar) where VAR is defined as a scalar string/number or a map rather than an array; also occurs when a dynamic variable returns a non-list value.

Common situations: Typo pointing the matrix ref at the wrong variable, a dynamic taskfile cmd returning JSON object instead of array, refactor renamed a list variable to a scalar, or YAML quoting turning an intended list into a string.

Related errors


AI-assisted analysis of go-task/task@385e5ad92a (2026-09-05). Data as JSON: /api/errors/0bc0c3aecb26a116. Report an issue: GitHub.