apple/pkl · error · VmException
expectedNonEmptyCollection
expectedNonEmptyCollection
Error message
expectedNonEmptyCollection
What it means
Pkl's non-empty collection types (`NonEmptyList`, `NonEmptySet`, `NonEmptyMap`, `NonEmptyString`) enforce their invariant lazily: `VmCollection.checkNonEmpty` throws `expectedNonEmptyCollection` as soon as an empty collection is constructed or accessed. The error carries the offending collection as program value `Collection`, so an empty value reached a non-empty-typed slot.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/runtime/VmCollection.java:52
public abstract boolean isEmpty();
@Override
public boolean isSequence() {
return true;
}
public abstract VmCollection add(Object element);
public abstract VmCollection concatenate(VmCollection other);
public abstract Iterator<Object> reverseIterator();
public abstract Builder<? extends VmCollection> builder();
public final void checkNonEmpty() {
if (isEmpty()) {
CompilerDirectives.transferToInterpreter();
throw new VmExceptionBuilder()
.evalError("expectedNonEmptyCollection")
.withProgramValue("Collection", this)
.build();
}
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public abstract boolean isLengthOne();
public final void checkLengthOne() {
if (!isLengthOne()) {
CompilerDirectives.transferToInterpreter();
throw new VmExceptionBuilder()
.evalError("expectedSingleElementCollection")
.withProgramValue("Collection", this)
.build();
}
}View on GitHub (pinned to f3efcbfc9b)
Solutions
- Supply at least one element to the collection at the reported property.
- Relax the schema type from the non-empty variant (`Listing!`/`Mapping!`) to `Listing`/`Mapping` if emptiness is legitimate.
- Add a conditional/default so an empty result falls back to a populated value instead of the non-empty type.
- Inspect the `Collection` value attached to the error to find exactly which property was empty.
Example fix
// before
hosts: NonEmptyList<String> = List.empty // error
// after
hosts: NonEmptyList<String> = List("localhost") Defensive patterns
Strategy: validation
Validate before calling
// validate before assigning to a non-empty-typed property
if (hosts.isEmpty()) {
throw new IllegalArgumentException("hosts must contain at least one entry");
} Type guard
boolean isNonEmpty(List<?> list) { return list != null && !list.isEmpty(); } Try / catch
catch (EvalError e) {
if (e.getMessage().contains("expectedNonEmptyCollection")) {
// inspect the 'Collection' program value; provide a default non-empty value
}
} Prevention
- Give non-empty-typed properties a populated default value in the schema.
- Guard filtered/derived listings against becoming empty before binding them to non-empty types.
- Only use NonEmpty* types when emptiness is genuinely invalid.
When it happens
Trigger: Amending/constructing a `Listing!`, `Mapping!`, `Set!`, or `String!` (non-empty variants) with zero elements; passing an empty List/Set/Map/Expr where a non-empty type is required; a `Listing!` whose contents are filtered down to nothing.
Common situations: Schema declares `serverHosts: NonEmptyList<String>` but the config renders an empty list; an environment with no matching entries produces an empty listing; default values that are empty lists assigned to non-empty typed properties.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/a683227421c1360a.
Report an issue: GitHub.