apple/pkl · error · RendererException

Maps containing non-String keys cannot be rendered as JSON.

Error message

Maps containing non-String keys cannot be rendered as JSON. Key: %s

What it means

The Pkl JSON renderer refuses to serialize any Map whose keys are not Java Strings, because JSON object keys must be strings and the renderer does not silently coerce other key types. It pre-scans all keys in visitMap and throws a RendererException naming the offending key before writing any output.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/JsonRenderer.java:140

        throw new UncheckedIOException(e);
      }
    }

    @Override
    public void visitList(List<?> value) {
      doVisitCollection(value);
    }

    @Override
    public void visitSet(Set<?> value) {
      doVisitCollection(value);
    }

    @Override
    public void visitMap(Map<?, ?> value) {
      for (var key : value.keySet()) {
        if (!(key instanceof String)) {
          throw new RendererException(
              String.format(
                  "Maps containing non-String keys cannot be rendered as JSON. Key: %s", key));
        }
      }

      @SuppressWarnings("unchecked")
      var mapValue = (Map<String, ?>) value;
      doVisitProperties(mapValue);
    }

    @Override
    public void visitObject(PObject value) {
      doVisitProperties(value.getProperties());
    }

    @Override
    public void visitModule(PModule value) {
      doVisitProperties(value.getProperties());

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Change the mapping keys to String in the Pkl source (quote them: `["8080"] { ... }`)
  2. Convert numeric/other keys to strings before rendering, e.g. iterate and build a new mapping with `key.toString()` keys
  3. Render to a format that supports non-string keys (Pkl, YAML, or custom renderer) instead of JSON

Example fix

// before (Pkl)
ports {
  [8080] { name = "http" }
}
// after (Pkl)
ports {
  ["8080"] { name = "http" }
}
Defensive patterns

Strategy: validation

Validate before calling

boolean jsonSafe(Object map) {
  return map instanceof Map<?,?> m && m.keySet().stream().allMatch(k -> k instanceof String);
}

Type guard

static boolean hasStringKeys(Map<?,?> m) {
  return m.keySet().stream().allMatch(k -> k instanceof String);
}

Prevention

When it happens

Trigger: Calling JSON rendering (e.g. via renderer output `json` or JsonRenderer) on a Pkl mapping/object that has non-String keys, such as Int, Float, Boolean or enum keys — e.g. a `Mapping<Int>` or an object with typed non-String key properties.

Common situations: Converting Pkl configs with numeric lookup tables (port -> value, ID -> value) to JSON; using YAML-style integer keys that were legal in another output format; library code building Maps with typed keys and rendering them as JSON.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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