apple/pkl · error

operatorNotDefined1

operatorNotDefined1

Error message

operatorNotDefined1

What it means

Pkl raises `operatorNotDefined1` when a unary operator is applied to an operand whose type does not support it. The UnaryExpressionNode family (e.g. UnaryMinusNode, LogicalNotNode) uses Truffle specializations per type; when no specialization matches, the @Fallback at UnaryExpressionNode.java:34 throws an eval error naming the operator and the operand's class. This is Pkl's way of saying the operand type has no defined semantics for that operator.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/ast/expression/unary/UnaryExpressionNode.java:34

package org.pkl.core.ast.expression.unary;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.source.SourceSection;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.runtime.VmUtils;

@NodeChild(value = "operandNode", type = ExpressionNode.class)
public abstract class UnaryExpressionNode extends ExpressionNode {
  protected UnaryExpressionNode(SourceSection sourceSection) {
    super(sourceSection);
  }

  @Fallback
  @TruffleBoundary
  protected Object fallback(Object operand) {
    throw exceptionBuilder()
        .evalError("operatorNotDefined1", getShortName(), VmUtils.getClass(operand))
        .withProgramValue("Operand", operand)
        .build();
  }
}

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Read the error message: it names the operator and the operand's class; locate the operand expression at the reported source location and confirm its actual type.
  2. Convert or fix the operand so it has the type the operator expects (e.g. use `value.toBoolean()` style conversion or fix the value so `-` applies to Int/Float and `!` applies to Boolean).
  3. If the operand can legitimately be absent/null, guard the expression, e.g. use the null-propagating form or a conditional instead of the raw operator.
  4. If the type is dynamic (external input), add an `is`-based type check or a `when`/amend block so the operator is only applied to matching values.

Example fix

// before (pkl)
flag: !input.enabled   // input.enabled is a String "yes" -> operatorNotDefined1

// after
flag: !input.enabled.toBoolean()
Defensive patterns

Strategy: type-guard

Validate before calling

// pkl
if (value is Int || value is Float) { /* safe for unary minus */ }
if (value is Boolean) { /* safe for ! */ }

Type guard

function isNumeric(x) = x is Int || x is Float
function isBool(x) = x is Boolean

Prevention

When it happens

Trigger: Evaluating a unary operator in Pkl code where the operand type is not covered by any specialization, e.g. `-"abc"` (unary minus on String), `!42` (logical not on Int), or applying a unary operator to a Listing/Mapping/typed object or null where no specialization exists. `getShortName()` supplies the operator symbol and `VmUtils.getClass(operand)` supplies the offending operand type in the message.

Common situations: A property intended to be a number is actually a String (so `-value` fails); a boolean property reads null or a non-Boolean from an environment override so `!flag` fails; refactored code changed a property's type (Int -> String) leaving a unary expression behind; applying `!` to the result of a comparison that was removed during editing.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/3883f2e79292536b. Report an issue: GitHub.