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
- Inspect the referenced variable and change its definition to a list (YAML sequence or JSON array).
- If it is a dynamic variable, make the command output a JSON array of values.
- Correct the matrix ref in the `for` section so it points at the list variable you intended.
- 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
- Keep matrix-source variables as YAML sequences only.
- For dynamic variables, always emit JSON arrays.
- After refactors, grep for matrix refs and re-verify target variable types.
- Add a unit test asserting the matrix variable's type.
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
- task: Blank Arch value provided
- task: Multiple Arch values provided
- task: Invalid Arch value provided (%s)
- enum reference %q must resolve to a list
- task: precondition not met
AI-assisted analysis of go-task/task@385e5ad92a (2026-09-05).
Data as JSON: /api/errors/0bc0c3aecb26a116.
Report an issue: GitHub.