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

  1. Convert non-string keys to strings before rendering: `[key.toString()] = value`.
  2. Zero-pad or format integer keys deliberately (e.g. `"\(key)"`) so output is stable.
  3. Use a Listing of pairs/objects instead of a Map if keys are inherently non-string.
  4. 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

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


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