{"record":{"id":"38491dd5e88f6ac3","repo":"apple/pkl","slug":"operatornotdefinedleft","errorCode":"operatorNotDefinedLeft","errorMessage":"operatorNotDefinedLeft ${op} ${leftClass}","messagePattern":"operatorNotDefinedLeft (.+?) (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/ast/expression/binary/ShortCircuitingExpressionNode.java","lineNumber":44,"sourceCode":"/**\n * A binary expression whose right operand may be short-circuited. Does not inherit from\n * BinaryExpressionNode for technical reasons.\n */\n@NodeChild(value = \"leftNode\", type = ExpressionNode.class)\npublic abstract class ShortCircuitingExpressionNode extends ExpressionNode {\n  @Child protected ExpressionNode rightNode;\n\n  protected abstract ExpressionNode getLeftNode();\n\n  protected ShortCircuitingExpressionNode(SourceSection sourceSection, ExpressionNode rightNode) {\n    super(sourceSection);\n    this.rightNode = rightNode;\n  }\n\n  @Fallback\n  @TruffleBoundary\n  protected Object fallback(Object left) {\n    throw operatorNotDefined(left);\n  }\n\n  @TruffleBoundary\n  protected VmException operatorNotDefined(Object left) {\n    return exceptionBuilder()\n        .evalError(\"operatorNotDefinedLeft\", getShortName(), VmUtils.getClass(left))\n        .withProgramValue(\"Left operand\", left)\n        .build();\n  }\n\n  @TruffleBoundary\n  protected VmException operatorNotDefined(Object left, Object right) {\n    return exceptionBuilder()\n        .evalError(\n            \"operatorNotDefined2\", getShortName(), VmUtils.getClass(left), VmUtils.getClass(right))\n        .withProgramValue(\"Left operand\", left)\n        .withProgramValue(\"Right operand\", right)\n        .build();","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/ast/expression/binary/ShortCircuitingExpressionNode.java#L26-L62","documentation":"Short-circuiting nodes (`&&`, `||`) require the left operand to be Boolean; when no specialization matches the left type, the fallback throws `operatorNotDefinedLeft` naming the operator and the left operand's class. Unlike 542/543 (right side), here the LEFT side of the logical operator is not a Boolean.","triggerScenarios":"`<nonBoolean> && ...` or `<nonBoolean> || ...`, e.g. `1 && true`, `\"yes\" || false`, or a lazily-evaluated left property of wrong type.","commonSituations":"Condition written against a config property whose type changed (Int/String instead of Boolean), or inverted/missing comparison.","solutions":["Fix the left operand to be a Boolean expression","Add the missing comparison that converts the value to Boolean","Annotate the source property as Boolean"],"exampleFix":"// before (Pkl)\nval ok = retries && retries > 3\n// after\nval ok = retries > 0 && retries > 3","handlingStrategy":"type-guard","validationCode":"function isValidLeftOperand(left) { return typeof left === 'boolean'; }","typeGuard":"const isBool = (v) => typeof v === 'boolean';","tryCatchPattern":null,"preventionTips":["Check the LEFT side of &&/|| is a Boolean expression","Fix inverted or missing comparisons","Type-annotate source properties as Boolean"],"tags":["logical-operator","type-error","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"}