nektos/act · error

the workflow is not valid. Matrix exclude key %q does not ma

Error message

the workflow is not valid. Matrix exclude key %q does not match any key within the matrix

What it means

During matrix expansion, act verifies every key used in a `matrix.exclude` entry exists as a top-level matrix key. GitHub fails hard on exclude entries referencing undefined matrix keys (but silently skips non-matching include entries), and act replicates that behavior by returning this error.

Source

Thrown at pkg/model/workflow.go:432

						i := i.(map[string]interface{})
						includes = append(includes, i)
					}
				case interface{}:
					v := v.(map[string]interface{})
					includes = append(includes, v)
				}
			}
			delete(m, "include")

			excludes := make([]map[string]interface{}, 0)
			for _, e := range m["exclude"] {
				e := e.(map[string]interface{})
				for k := range e {
					if _, ok := m[k]; ok {
						excludes = append(excludes, e)
					} else {
						// We fail completely here because that's what GitHub does for non-existing matrix keys, fail on exclude, silent skip on include
						return nil, fmt.Errorf("the workflow is not valid. Matrix exclude key %q does not match any key within the matrix", k)
					}
				}
			}
			delete(m, "exclude")

			matrixProduct := common.CartesianProduct(m)
		MATRIX:
			for _, matrix := range matrixProduct {
				for _, exclude := range excludes {
					if commonKeysMatch(matrix, exclude) {
						log.Debugf("Skipping matrix '%v' due to exclude '%v'", matrix, exclude)
						continue MATRIX
					}
				}
				matrixes = append(matrixes, matrix)
			}
			for _, include := range includes {
				matched := false

View on GitHub (pinned to 4f41128141)

Solutions

  1. Align every key in each exclude entry with the matrix's top-level dimensions.
  2. Fix typos in exclude key names to match matrix keys exactly (case-sensitive).
  3. For value-based exclusions, ensure the value belongs to the defined matrix array — the key must exist even if the value combination never occurs (GitHub then simply skips it).

Example fix

# before
matrix:
  os: [ubuntu-latest, macos-latest]
  node: [18, 20]
  exclude:
    - os: macos-latest
      env: prod   # 'env' is not a matrix key
# after
matrix:
  os: [ubuntu-latest, macos-latest]
  node: [18, 20]
  exclude:
    - os: macos-latest
      node: 18
Defensive patterns

Strategy: validation

Validate before calling

func validateExcludeKeys(matrix map[string]interface{}) error {
    for _, e := range toSlice(matrix["exclude"]) {
        m, ok := e.(map[string]interface{})
        if !ok { continue }
        for k := range m {
            if _, ok := matrix[k]; !ok {
                return fmt.Errorf("exclude key %q not in matrix", k)
            }
        }
    }
    return nil
}

Prevention

When it happens

Trigger: A matrix defines os: [ubuntu-latest] and node: [20], but an exclude entry uses `{ os: windows-latest, foo: bar }` — key `foo` is not a matrix key, so expansion aborts. Also triggered by typos in exclude keys (`noded` instead of `node`).

Common situations: Copying exclude blocks from another workflow whose matrix has different keys; renaming a matrix dimension without updating excludes; excluding on a value that was moved into an include-generated dimension.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/b8f9bde024cc0dee. Report an issue: GitHub.