apple/pkl · error
expectedNonNullValue
expectedNonNullValue
Error message
expectedNonNullValue
What it means
Thrown by the non-null assertion operator `!!` when its operand evaluates to null. The error is reported at the operand's source section so the developer can see which expression was null. Pkl's `!!` is a deliberate runtime assertion that a value is non-null.
Solutions
- Look at the highlighted operand expression; check why it evaluates to null.
- Replace `!!` with an explicit null check or use `??` to supply a default value.
- If the operand is an absent property, ensure the upstream module actually defines/sets it.
- Use `isNonNullable`/instanceof tests to guard before applying `!!`.
Example fix
// before val port = externalConfig?.port!! // after val port = externalConfig?.port ?? 8080
Defensive patterns
Strategy: type-guard
Validate before calling
val port = if (cfg?.port != null) cfg.port else 8080
Type guard
function requireNonNull<T>(v: T|null, msg: String): T = if (v == null) throw new Error(msg) else v
Try / catch
try {
value = operand!!
} catch (e) {
// e.code === 'expectedNonNullValue': operand was null; supply default
} Prevention
- Prefer `??` defaults over bare `!!`
- Check optional properties with `!= null` before asserting
- Avoid `!!` on values derived from external input
When it happens
Trigger: Evaluating `x!!` where `x` is null — e.g. an optional property that was never set, a `read()` on a missing resource returning null, or a Map/List lookup producing null followed by `!!`.
Common situations: Asserting non-null on property lookups that may be absent, parsing external data with optional fields, using `!!` defensively instead of providing defaults.
Related errors
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/417d64ee227e2d47.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/expression/unary/NonNullNode.java:41
import org.pkl.core.runtime.VmNull;
@NodeInfo(shortName = "!!")
// Truffle DSL/codegen is overkill for this node, hence don't extend UnaryExpressionNode
public final class NonNullNode extends ExpressionNode {
private @Child ExpressionNode operandNode;
public NonNullNode(SourceSection sourceSection, ExpressionNode operandNode) {
super(sourceSection);
this.operandNode = operandNode;
}
@Override
public Object executeGeneric(VirtualFrame frame) {
var operand = operandNode.executeGeneric(frame);
if (!(operand instanceof VmNull)) return operand;
CompilerDirectives.transferToInterpreter();
throw exceptionBuilder()
.evalError("expectedNonNullValue")
.withSourceSection(operandNode.getSourceSection())
.build();
}
}
View on GitHub (pinned to f3efcbfc9b)