apple/pkl · error
operatorNotDefined2
operatorNotDefined2
Error message
operatorNotDefined2 ${op} ${leftClass} ${rightClass} What it means
Generic binary-operator fallback in Truffle DSL specializations: when no typed specialization matches the operand types, Pkl throws `operatorNotDefined2` naming the operator and both operand classes. It means the operator is simply not defined for that type combination. This is a type error discovered at evaluation time rather than a runtime bug.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/expression/binary/BinaryExpressionNode.java:39
import com.oracle.truffle.api.source.SourceSection;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.runtime.VmUtils;
@NodeChild(value = "leftNode", type = ExpressionNode.class)
@NodeChild(value = "rightNode", type = ExpressionNode.class)
public abstract class BinaryExpressionNode extends ExpressionNode {
protected BinaryExpressionNode(SourceSection sourceSection) {
super(sourceSection);
}
protected abstract ExpressionNode getLeftNode();
protected abstract ExpressionNode getRightNode();
@Fallback
@TruffleBoundary
protected Object fallback(Object left, Object right) {
throw exceptionBuilder()
.evalError(
"operatorNotDefined2", getShortName(), VmUtils.getClass(left), VmUtils.getClass(right))
.withProgramValue("Left operand", left)
.withProgramValue("Right operand", right)
.build();
}
}
View on GitHub (pinned to f3efcbfc9b)
Solutions
- Check the dynamic types of both operands and fix the expression or its declared type
- Use explicit conversions (`toInt()`, `toString()`, string interpolation) instead of relying on coercion
- Add a type annotation on the property so the mistake is caught earlier
Example fix
// before (Pkl) val x = "count: " + 5 - 1 // after val x = "count: " + (5 - 1).toString()
Defensive patterns
Strategy: type-guard
Validate before calling
function operandsCompatible(op, l, r) {
if (typeof l === 'string' || typeof r === 'string') return op === '+' || op === '==';
return typeof l === 'number' && typeof r === 'number';
} Type guard
const bothNumeric = (l, r) => typeof l === 'number' && typeof r === 'number'; const bothString = (l, r) => typeof l === 'string' && typeof r === 'string';
Prevention
- Annotate property types in Pkl so operator misuse fails at type-check
- Convert explicitly with toInt()/toString() instead of relying on coercion
- Avoid operating on `any`-typed values without narrowing
When it happens
Trigger: Applying a binary operator (e.g. `+`, `-`, `<`) to operand types with no matching specialization, such as `"a" - "b"` or `[1] * 2` where no overload exists.
Common situations: Typos in intended operator, mixing String and Number assuming implicit coercion, or calling an operator on a value typed `any`/`unknown` whose dynamic type lacks the operator.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- operatorNotDefined2
- operatorNotDefined2
- operatorNotDefinedLeft
- operatorNotDefined1
- Node `%s` of type `%s` does not have a property named `%s`.
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/3a6ec0b2705f8771.
Report an issue: GitHub.