apple/pkl · error · ConversionException

Error invoking constructor of class `%s`.

Error message

Error invoking constructor of class `%s`.

What it means

PMapToMap maps a Pkl Map value to a Java Map implementation chosen by the requested target type. It instantiates the target map class via reflection, preferring a (int capacity, float loadFactor) constructor and passing (length/0.75f)+1 and 0.75f. This ConversionException wraps any Throwable thrown while invoking that two-argument constructor, such as an IllegalArgumentException from a constructor that rejects those arguments or an InvocationTargetException from constructor logic.

Source

Thrown at pkl-config-java/src/main/java/org/pkl/config/java/mapper/PMapToMap.java:65

    var typeArguments = mapType.getActualTypeArguments();
    var keyType = Reflection.normalize(typeArguments[0]);
    var valueType = Reflection.normalize(typeArguments[1]);
    return createInstantiator(targetClass)
        .map(instantiator -> new ConverterImpl<>(instantiator, keyType, valueType));
  }

  private <K, V> Optional<Function<Integer, Map<K, V>>> createInstantiator(Class<?> clazz) {
    try {
      // constructor with capacity and load factor arguments
      var ctor2 =
          lookup.findConstructor(clazz, MethodType.methodType(void.class, int.class, float.class));
      return Optional.of(
          length -> {
            try {
              //noinspection unchecked
              return (Map<K, V>) ctor2.invoke((int) (length / .75f) + 1, .75f);
            } catch (Throwable t) {
              throw new ConversionException(
                  String.format("Error invoking constructor of class `%s`.", clazz), t);
            }
          });
    } catch (NoSuchMethodException e2) {
      try {
        // default constructor
        var ctor0 = lookup.findConstructor(clazz, MethodType.methodType(void.class));
        return Optional.of(
            length -> {
              try {
                //noinspection unchecked
                return (Map<K, V>) ctor0.invoke();
              } catch (Throwable t) {
                throw new ConversionException(
                    String.format("Error invoking constructor of class `%s`.", clazz), t);
              }
            });
      } catch (NoSuchMethodException e0) {

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Check the cause (`e.getCause()`) to see why the (int,float) constructor threw; fix the custom map class so its (int, float) constructor accepts initialCapacity and loadFactor semantics.
  2. Add a no-arg constructor to your Map class so PMapToMap falls back to `createInstantiator`'s default-constructor path instead of the (int,float) constructor.
  3. Map to a standard map type (java.util.HashMap, LinkedHashMap, TreeMap, SortedMap) whose (int,float) constructor is well-behaved.
  4. If the constructor throws only for large inputs, reduce the size of the Pkl map or raise the limit inside the constructor.

Example fix

// before
class Sizes extends HashMap<String, Integer> {
  Sizes(int maxEntries, float unused) { super(maxEntries); if (maxEntries > 1000) throw new IllegalArgumentException("too big"); }
}
// after
class Sizes extends HashMap<String, Integer> {
  Sizes(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } // accept JDK semantics
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before conversion, verify the target map class has a well-behaved (int, float) constructor:
static boolean hasSafeCapacityCtor(Class<?> c) {
  try {
    var ctor = c.getConstructor(int.class, float.class);
    var inst = ctor.newInstance(4, 0.75f); // smoke-test invocation
    inst.getClass().cast(inst);
    return true;
  } catch (ReflectiveOperationException | RuntimeException e) {
    return false;
  }
}

Type guard

static boolean isStandardMap(Class<?> c) {
  return java.util.HashMap.class.isAssignableFrom(c)
      || java.util.LinkedHashMap.class.isAssignableFrom(c)
      || java.util.TreeMap.class.isAssignableFrom(c);
}

Try / catch

try {
  Map<String, Object> result = valueRenderer.render(pValue, my.CustomMap.class);
} catch (ConversionException e) {
  Throwable cause = e.getCause();
  log.error("Constructor of " + cause + " failed; falling back to HashMap", e);
  Map<String, Object> result = new java.util.LinkedHashMap<>(); // fallback
}

Prevention

When it happens

Trigger: Requesting a mapping to a Map subtype whose (int, float) constructor exists but fails when invoked during conversion, e.g. `ValueRenderer.render(config, my.CustomMap.class)` or DataFleet/Config conversions where CustomMap's (int,float) constructor validates its arguments or throws internally.

Common situations: Custom Map implementations whose capacity/load-factor constructor has different semantics (e.g. expects maxCapacity, not initialCapacity, and throws IllegalArgumentException for large sizes); constructors that throw on negative or oversized capacity for huge Pkl maps; constructors with side-effectful initialization that fails.

Related errors


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