apple/pkl · error · VmException
cannotRenderNonStringMap
cannotRenderNonStringMap
Error message
cannotRenderNonStringMap
What it means
When rendering a Map, all keys must be strings (or, for objects, valid member names). cannotRenderNonStringKey detects a non-String key while the enclosing value is a VmMap and throws cannotRenderNonStringMap, because target formats like YAML/JSON/PList map keys must be strings. The offending key is attached to the error as program value `Key`.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/stdlib/AbstractRenderer.java:435
@Override
public void visitTypeAlias(VmTypeAlias value) {
cannotRenderTypeAddConverter(value);
}
@Override
public void visitClass(VmClass value) {
cannotRenderTypeAddConverter(value);
}
@Override
public void visitFunction(VmFunction value) {
cannotRenderTypeAddConverter(value);
}
protected void cannotRenderNonStringKey(Object key) {
assert enclosingValue != null;
var isMap = enclosingValue instanceof VmMap;
throw new VmExceptionBuilder()
.evalError(isMap ? "cannotRenderNonStringMap" : "cannotRenderObjectWithNonStringKey", name)
.withProgramValue(isMap ? "Map" : "Object", enclosingValue)
.withProgramValue("Key", key)
.build();
}
protected void cannotRenderNonScalarKey(Object key) {
assert enclosingValue != null;
var isMap = enclosingValue instanceof VmMap;
throw new VmExceptionBuilder()
.evalError(isMap ? "cannotRenderNonScalarMap" : "cannotRenderObjectWithNonScalarKey", name)
.withProgramValue(isMap ? "Map" : "Object", enclosingValue)
.withProgramValue("Key", key)
.build();
}
}
View on GitHub (pinned to f3efcbfc9b)
Solutions
- Convert non-string keys to strings before rendering: `[key.toString()] = value`.
- Zero-pad or format integer keys deliberately (e.g. `"\(key)"`) so output is stable.
- Use a Listing of pairs/objects instead of a Map if keys are inherently non-string.
- Check upstream data (parsed files, computed maps) for non-string keys.
Example fix
// before
output.value = Map(8080, "http") // Int key rendered as JSON
// after
output.value = Map("8080", "http") Defensive patterns
Strategy: validation
Validate before calling
// assert all keys are strings before rendering function hasStringKeys(m: Map) = m.keys.every((k) -> k is String)
Try / catch
try { render(mapValue) } catch (e) { if (e.message.contains('cannotRenderNonStringMap')) render(stringifyKeys(mapValue)) else throw e } Prevention
- Always build rendered maps with string keys
- Stringify numeric keys deliberately (with zero-padding if order matters)
- Audit maps built from parsed external data for key types
When it happens
Trigger: Rendering a Map whose keys are non-String values (Int, Duration, Regex, etc.) via a renderer such as YamlRenderer, JsonRenderer, or PList renderer.
Common situations: Building a Map with integer keys (e.g. ports or indexes) and rendering it as JSON/YAML output; using durations or numbers as keys after a refactor; converting dynamic data that used numeric keys.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- cannotRenderNonScalarMap
- cannotRenderObjectWithElementsAndOtherMembers
- Values of type `Duration` cannot be rendered as JSON. Value:
- Values of type `DataSize` cannot be rendered as JSON. Value:
- Values of type `Bytes` cannot be rendered as JSON. Value: %s
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/6861f6a3e9b2918f.
Report an issue: GitHub.