{"record":{"id":"3a6ec0b2705f8771","repo":"apple/pkl","slug":"operatornotdefined2","errorCode":"operatorNotDefined2","errorMessage":"operatorNotDefined2 ${op} ${leftClass} ${rightClass}","messagePattern":"operatorNotDefined2 (.+?) (.+?) (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/ast/expression/binary/BinaryExpressionNode.java","lineNumber":39,"sourceCode":"import com.oracle.truffle.api.source.SourceSection;\nimport org.pkl.core.ast.ExpressionNode;\nimport org.pkl.core.runtime.VmUtils;\n\n@NodeChild(value = \"leftNode\", type = ExpressionNode.class)\n@NodeChild(value = \"rightNode\", type = ExpressionNode.class)\npublic abstract class BinaryExpressionNode extends ExpressionNode {\n  protected BinaryExpressionNode(SourceSection sourceSection) {\n    super(sourceSection);\n  }\n\n  protected abstract ExpressionNode getLeftNode();\n\n  protected abstract ExpressionNode getRightNode();\n\n  @Fallback\n  @TruffleBoundary\n  protected Object fallback(Object left, Object right) {\n    throw exceptionBuilder()\n        .evalError(\n            \"operatorNotDefined2\", getShortName(), VmUtils.getClass(left), VmUtils.getClass(right))\n        .withProgramValue(\"Left operand\", left)\n        .withProgramValue(\"Right operand\", right)\n        .build();\n  }\n}\n","sourceCodeStart":21,"sourceCodeEnd":47,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/ast/expression/binary/BinaryExpressionNode.java#L21-L47","documentation":"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.","triggerScenarios":"Applying a binary operator (e.g. `+`, `-`, `<`) to operand types with no matching specialization, such as `\"a\" - \"b\"` or `[1] * 2` where no overload exists.","commonSituations":"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.","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"],"exampleFix":"// before (Pkl)\nval x = \"count: \" + 5 - 1\n// after\nval x = \"count: \" + (5 - 1).toString()","handlingStrategy":"type-guard","validationCode":"function operandsCompatible(op, l, r) {\n  if (typeof l === 'string' || typeof r === 'string') return op === '+' || op === '==';\n  return typeof l === 'number' && typeof r === 'number';\n}","typeGuard":"const bothNumeric = (l, r) => typeof l === 'number' && typeof r === 'number';\nconst bothString = (l, r) => typeof l === 'string' && typeof r === 'string';","tryCatchPattern":null,"preventionTips":["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"],"tags":["type-error","operator","pkl"],"backgroundTag":"type-mismatch","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}