apple/pkl · error · VmException
propertyMustBeConst
propertyMustBeConst
Error message
Cannot reference property `{0}` from here because it is not `const`. What it means
ReadSuperPropertyNode resolves `super.prop` by walking up the owner chain from the current owner. When the read site requires a const value (needsConst), it rejects any resolved member that is not declared `const`, throwing propertyMustBeConst. This guarantees `super` references used in const contexts cannot observe values that differ per amending object.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadSuperPropertyNode.java:60
var receiver = VmUtils.getObjectReceiver(frame);
// start from the parent of the owner of the `super.<propertyName>` expression
// skip any function object owners (same as when resolving `this`)
// `receiver` must be passed on unchanged to make sure that overridden properties still take
// effect
var initialOwner = VmUtils.getOwner(frame);
while (initialOwner instanceof VmFunction) {
initialOwner = initialOwner.getEnclosingOwner();
}
assert initialOwner != null : "VmFunction always has a parent";
initialOwner = initialOwner.getParent();
for (var owner = initialOwner; owner != null; owner = owner.getParent()) {
var property = owner.getMember(propertyName);
if (property == null) continue;
if (needsConst && !property.isConst()) {
CompilerDirectives.transferToInterpreter();
throw exceptionBuilder().evalError("propertyMustBeConst", propertyName.toString()).build();
}
var constantValue = property.getConstantValue();
if (constantValue != null) return constantValue; // TODO: type check
// caching the result of a super call is tricky (function of both receiver and owner)
return callNode.call(
property.getCallTarget(),
// TODO: should the marker only turn off constraint checking, not overall type checking?
receiver,
owner,
propertyName,
VmUtils.SKIP_TYPECHECK_MARKER);
}
// TODO: refine when to return VmDynamic.empty() and when to fail
return VmDynamic.empty();
}View on GitHub (pinned to f3efcbfc9b)
Solutions
- Declare the parent's property `const` (e.g. `const baseValue: Int = 10` in the superclass)
- Copy the needed value into a local const or literal instead of reading it via `super`
- Change the reading member so it does not require const (drop the `const`/`fixed` qualifier)
- Restructure inheritance so the const value lives in a shared const definition both classes reference
Example fix
// before
open class Base {
port: Int = 8080
}
class Derived extends Base {
const defaultPort: Int = super.port // ERROR
}
// after
open class Base {
const port: Int = 8080
}
class Derived extends Base {
const defaultPort: Int = super.port
} Defensive patterns
Strategy: validation
Validate before calling
// before writing `super.prop` in a const member, confirm the superclass declares it const:
// open class Base { const prop: Int = ... } Type guard
null
Try / catch
null
Prevention
- Keep inherited values consumed via `super` declared `const` in base classes
- Avoid `super` reads inside const/fixed members; use direct literal consts instead
- Document const-ness contracts on open base classes
When it happens
Trigger: Writing `super.someProp` inside a `const` (or other needsConst) member where `someProp` is defined non-const in a parent class or enclosing object; executeGeneric walks owner.getParent() and finds the member but its isConst() is false.
Common situations: `const x: Int = super.baseValue` where the superclass declares `baseValue` as a normal property; migrating code that changed `super.foo` context to `fixed`/`const` after a refactor.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- cannotInvokeSupermethodFromHere
- propertyMustBeConst
- Node `%s` of type `%s` does not have a property named `%s`.
- JavaType token must be parameterized.
- Leaf node `%s` of type `%s` does not have a child named `%s`
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/f68b964de69fbd65.
Report an issue: GitHub.