apple/pkl · error · VmException
invalidProtobufTopLevelValue
invalidProtobufTopLevelValue
Error message
invalidProtobufTopLevelValue
What it means
The Protobuf renderer rejects top-level values that are internal Pkl value kinds (VmValue subclasses) other than Typed objects and Duration. Values like IntSeq, Pair, Regex, etc. have no protobuf mapping at the document root, and the error reports the stripped Vm-prefixed class name.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java:167
public ProtobufRenderer(StringBuilder builder, String indent, PklConverter converter) {
super("Protobuf", builder, indent, converter, true, true);
}
@Override
protected void visitDocument(Object value) {
visit(value);
startNewLine();
}
@Override
protected void visitTopLevelValue(Object value) {
if (value instanceof VmValue && !(value instanceof VmTyped || value instanceof VmDuration)) {
var name = value.getClass().getSimpleName();
if (name.startsWith("Vm")) {
name = name.substring(2);
}
throw new VmExceptionBuilder().evalError("invalidProtobufTopLevelValue", name).build();
}
assert propertyPath.isEmpty() && wrapperRequirement.isEmpty() : "Corrupted traversal stack.";
wrapperRequirement.push(false);
visit(value);
var wrap = wrapperRequirement.pop();
assert !wrap && propertyPath.isEmpty() && wrapperRequirement.isEmpty()
: "Corrupted traversal stack.";
}
@Override
protected void visitRenderDirective(VmTyped value) {
writePropertyName();
// append verbatim
builder.append(VmUtils.readTextProperty(value));
}
@Override
protected void startDynamic(VmDynamic value) {View on GitHub (pinned to f3efcbfc9b)
Solutions
- Render a typed object (module/class instance) as the top-level value
- Convert primitives/Duration-like values appropriately (Duration is allowed; e.g. wrap others in a typed object)
- Switch to JSON/Pcf/YAML renderer for non-object top-level values
Example fix
// before
output.value = Pair(1, 2)
output.renderer = new ProtobufRenderer
// after
output.value = new { pair = new Dynamic { first = 1; second = 2 } }
output.renderer = new ProtobufRenderer Defensive patterns
Strategy: validation
Validate before calling
function isProtobufTopLevel(v) { return isPklTyped(v) || isDuration(v); } Type guard
const isProtobufTopLevelOk = (v) => isPklTyped(v) || isPklDuration(v);
Try / catch
try { renderAsProtobuf(value) } catch (e) { if (e.code === 'invalidProtobufTopLevelValue') { /* wrap in typed object */ } else throw e } Prevention
- Use typed objects (or Duration) as protobuf top-level values
- Never render Pair/IntSeq/Regex etc. directly to protobuf
- When migrating renderers, re-check top-level value type per format
When it happens
Trigger: Calling protobuf rendering with a top-level value such as an IntSeq, Pair, Listing-internal value, Regex, or other non-Typed/non-Duration VmValue.
Common situations: Pointing a protobuf output at `output.value` that holds a Pkl collection or utility value instead of a typed object; migrating a renderer from JSON (permissive) to protobuf (restrictive).
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
- invalidPListTopLevelValue
- invalidPcfTopLevelValue
- invalidPropertiesTopLevelValue
- cannotResolveTypeForProtobuf
- cannotRenderTypeAddConverter
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/da98ad0240a09801.
Report an issue: GitHub.