apple/pkl · error · VmException

cannotRenderNonScalarMap

cannotRenderNonScalarMap

Error message

cannotRenderNonScalarMap

What it means

Renderer map keys must be scalar values. cannotRenderNonScalarKey throws cannotRenderNonScalarMap when the enclosing value is a VmMap and a key is a non-scalar (e.g. an object, listing, or collection). Target output formats cannot represent composite keys, so rendering aborts with the enclosing Map and offending Key attached.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/stdlib/AbstractRenderer.java:445

  @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

  1. Replace the composite key with a scalar: a String derived from it (e.g. its `toString()` or a stable id field).
  2. Use an identifying property of the object (e.g. `obj.name`) as the key instead of the object itself.
  3. If association of composite data is needed, store it as the value or in a Listing of pairs.
  4. Log/inspect the reported `Key` program value to find where the composite key originates.

Example fix

// before
Mapping { [List(1, 2)] = "pair" }

// after
Mapping { ["1-2"] = "pair" } // stringified scalar key
Defensive patterns

Strategy: validation

Validate before calling

// ensure keys are scalars before rendering
function hasScalarKeys(m: Map) = m.keys.every((k) -> k is String || k is Number || k is Boolean)

Try / catch

try { render(mapValue) } catch (e) { if (e.message.contains('cannotRenderNonScalarMap')) render(keyToId(mapValue)) else throw e }

Prevention

When it happens

Trigger: Rendering a Map that contains a key which is itself a non-scalar value such as a Dynamic object, Listing, Map, or other composite value.

Common situations: Using objects or collections as Map keys by accident; building indexes keyed by parsed structures; nested data conversion that placed a collection where a scalar key was expected.

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


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/fb7804954a167ee3. Report an issue: GitHub.