apple/pkl · error · VmException

cannotRenderProtobufMapKey

cannotRenderProtobufMapKey

Error message

cannotRenderProtobufMapKey

What it means

Protobuf map keys must be directives, Long, Boolean, or String; the renderer found a map entry key of another type (e.g. a Double, IntSeq, or arbitrary object) and aborts, attaching the offending key as program value.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java:313

      visit(value);
      var popped = wrapperRequirement.pop();
      assert popped : "Corrupted traversal stack.";
      if (addedType) {
        propertyPath.pop();
        endMessage();
      }
      if (requiresWrapper()) {
        propertyPath.pop();
      }
    }

    @Override
    protected void visitEntryKey(Object key, boolean isFirst) {
      var isDirective = isRenderDirective(key);
      var isValidKey =
          isDirective || key instanceof Long || key instanceof Boolean || key instanceof String;
      if (!isValidKey) {
        throw new VmExceptionBuilder()
            .evalError("cannotRenderProtobufMapKey")
            .withProgramValue("Key", key)
            .build();
      }
      writePropertyName();
      startMessage();
      startNewLine();
      builder.append("key: ");
      if (isDirective) {
        builder.append(VmUtils.readTextProperty(key));
      } else if (key instanceof String string) {
        builder.append('"').append(jsonEscaper.escape(string)).append('"');
      } else {
        builder.append(key);
      }
    }

    @Override

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Change map keys to String (or Long/Boolean), e.g. `["1.0"]` instead of `[1.0]`
  2. Convert key values before rendering (`key.toString()` / integer literals without decimal point)
  3. Exclude or transform non-conforming entries before protobuf rendering

Example fix

// before
value = new Mapping { [1.0] = "a" }
// after
value = new Mapping { ["1"] = "a" }
Defensive patterns

Strategy: validation

Validate before calling

function hasValidMapKeys(m) { return Object.values(m).every((entry) => typeof entry.key === 'string' || typeof entry.key === 'boolean' || Number.isInteger(entry.key)); }

Type guard

const isProtobufMapKey = (k) => typeof k === 'string' || typeof k === 'boolean' || Number.isInteger(k);

Try / catch

try { renderAsProtobuf(value) } catch (e) { if (e.code === 'cannotRenderProtobufProtobufKey' || e.code === 'cannotRenderProtobufMapKey') { /* coerce keys to String/Long */ } else throw e }

Prevention

When it happens

Trigger: Rendering a Mapping/Map to protobuf whose keys are not Long/Boolean/String — e.g. float keys, keys that are objects, or Defaultable/other Vm wrapper keys not recognized as directives.

Common situations: Using Pkl Mappings with non-string keys (numbers as Double from `1.0` literal, booleans via bracket syntax that resolves oddly) and rendering to protobuf; JSON-imported maps with numeric keys parsed as doubles.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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