nektos/act · error
Compare not implemented for types: left: %+v, right: %+v
Error message
Compare not implemented for types: left: %+v, right: %+v
What it means
Thrown by the expression interpreter when a comparison operator (<, >, <=, >=, ==) is applied to operand kinds the compare switch does not handle (e.g. arrays, objects/maps, structs, slices, channels, pointers). The interpreter coerces both operands to a common reflect.Kind before comparing, and only numbers, strings, bools, and Invalid are supported. Any other kind falls into the default branch and the error reports the offending reflect Kinds.
Source
Thrown at pkg/exprparser/interpreter.go:420
return impl.compareNumber(float64(leftValue.Int()), float64(rightValue.Int()), kind)
case reflect.Float64:
if rightValue.Kind() == reflect.Int {
return impl.compareNumber(leftValue.Float(), float64(rightValue.Int()), kind)
}
return impl.compareNumber(leftValue.Float(), rightValue.Float(), kind)
case reflect.Invalid:
if rightValue.Kind() == reflect.Invalid {
return true, nil
}
// not possible situation - params are converted to the same type in code above
return nil, fmt.Errorf("Compare params of Invalid type: left: %+v, right: %+v", leftValue.Kind(), rightValue.Kind())
default:
return nil, fmt.Errorf("Compare not implemented for types: left: %+v, right: %+v", leftValue.Kind(), rightValue.Kind())
}
}
func (impl *interperterImpl) coerceToNumber(value reflect.Value) reflect.Value {
switch value.Kind() {
case reflect.Invalid:
return reflect.ValueOf(0)
case reflect.Bool:
switch value.Bool() {
case true:
return reflect.ValueOf(1)
case false:
return reflect.ValueOf(0)
}
case reflect.String:
if value.String() == "" {View on GitHub (pinned to 4f41128141)
Solutions
- Extract a scalar field before comparing: `${{ fromJSON(x).version < fromJSON(y).version }}` instead of comparing whole objects.
- Convert operands with supported functions such as toJSON/fromJSON/format/number so both sides become strings or numbers.
- Replace the raw comparison with a function that handles composites, e.g. contains(join(arr, ','), 'val') instead of arr < other.
- If you control the expression surface, pre-validate operand types in Go with reflect.ValueOf(...).Kind() before invoking the interpreter.
Example fix
# before
if: ${{ matrix.cfg < matrix.other }}
# after
if: ${{ matrix.cfg.name < matrix.other.name }} Defensive patterns
Strategy: try-catch
Validate before calling
// before invoking the interpreter, verify both comparands are scalar
func isScalar(v interface{}) bool {
switch reflect.ValueOf(v).Kind() {
case reflect.Invalid, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16,
reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
return true
}
return false
} Try / catch
result, err := interpreter.Evaluate(expr)
if err != nil {
if strings.Contains(err.Error(), "Compare not implemented for types") {
// log and fall back to a string-based comparison or skip the condition
}
return err
} Prevention
- Never compare whole JSON objects/arrays in expressions; project scalar fields first with fromJSON(x).field.
- Lint workflow expressions for direct comparisons on matrix values known to be composite.
- In embedded use, reflect-check operand kinds before calling the interpreter.
When it happens
Trigger: Evaluating a workflow expression like `${{ fromJSON('{"a":1}') < fromJSON('{"a":2}') }}` or comparing a matrix value that resolved to a map/slice/array with a scalar or another object. Also triggered by comparing values whose dynamic types differ so the coercion lands on an unsupported kind (e.g. Struct vs String).
Common situations: Comparing JSON objects produced by fromJSON, comparing github event payloads (objects) instead of scalar fields, comparing two arrays from matrix generation, or comparing a null against a composite value in a way that skips the Invalid-Invalid early return.
Related errors
- Unable to compare incompatibles types '%s' and '%s'
- TODO: '%s' not implemented
- Invalid glob option %s, available option: '--follow-symbolic
- failed to insert node %v into mapping %v unexpected type %v
AI-assisted analysis of nektos/act@4f41128141 (2026-08-15).
Data as JSON: /api/errors/9730c94a50182c96.
Report an issue: GitHub.