apple/pkl · error · VmException
classMustBeLocal
classMustBeLocal
Error message
classMustBeLocal
What it means
When amending a module or object (`extends`/amendment position), Pkl requires that class definitions be `local` — a non-local class in an amendment would leak a new top-level type into the amended parent, which the language forbids. AstBuilder.visitClasses raises classMustBeLocal with the class header section when moduleInfo.isAmend() and the visited class member is not local.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/builder/AstBuilder.java:1779
List<Class> classes,
List<TypeAlias> typeAliases,
List<ClassProperty> properties,
Set<String> propertyNames,
ModuleInfo moduleInfo) {
var totalSize = imports.length + classes.size() + typeAliases.size() + properties.size();
var result = EconomicMaps.<Object, ObjectMember>create(totalSize);
for (var member : imports) {
checkDuplicateMember(member.getName(), member.getHeaderSection(), propertyNames);
EconomicMaps.put(result, member.getName(), member);
}
for (var clazz : classes) {
ObjectMember member = visitClass(clazz);
if (moduleInfo.isAmend() && !member.isLocal()) {
throw exceptionBuilder()
.evalError("classMustBeLocal")
.withSourceSection(member.getHeaderSection())
.build();
}
checkDuplicateMember(member.getName(), member.getHeaderSection(), propertyNames);
EconomicMaps.put(result, member.getName(), member);
}
for (var typeAlias : typeAliases) {
var member = visitTypeAlias(typeAlias);
if (moduleInfo.isAmend() && !member.isLocal()) {
throw exceptionBuilder()
.evalError("typeAliasMustBeLocal")
.withSourceSection(member.getHeaderSection())
.build();
}View on GitHub (pinned to f3efcbfc9b)
Solutions
- Add the `local` modifier: `local class Foo {}`.
- Move the class into the base module instead of the amendment.
- Convert the class to a type alias or function local if a full class is unnecessary.
Example fix
// before (in an amendment)
class Credentials { user: String }
// after
local class Credentials { user: String } Defensive patterns
Strategy: validation
Validate before calling
// Verify classes declared in amendment files are local:
if (isAmendmentFile(file) && line.matches("\\s*class\\s+\\w+.*")) {
report(file, lineNo, "classes in amendments must be `local`");
} Prevention
- Treat amendment files as value-override layers only; keep types in the base module.
- Grep overrides for bare `class ` declarations and prefix with `local`.
- Remember the rule: anything declaring a type (class/typealias) in an amendment needs `local`.
When it happens
Trigger: Writing a class inside a module amendment or object amendment (isAmend() == true) without the `local` modifier, e.g. `class Foo {}` at amendment top level.
Common situations: Creating an override/layer file that extends a base config and adding helper classes; migrating code from a base module into an amendment without realizing nested classes need `local`.
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
- typeAliasMustBeLocal
- nonLocalObjectPropertyCannotHaveTypeAnnotation
- abstractMethodInNonAbstractType
- cannotAmendPropertyDefinition
- cannotExtendExternalClass
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/a3b27b9c4b12ae83.
Report an issue: GitHub.