apple/pkl · error · ConversionException

Cannot convert ` ` to ` ` because no conversion was found.

Error message

Cannot convert `%s` to `%s` because no conversion was found.

What it means

After exhausting the registered converters and any type-mapping-based converter construction, getConverter gives up and throws ConversionException stating that no conversion path exists from the Pkl source type to the requested Java target type.

Solutions

  1. Register a Converter for the (source, target) pair via ValueConverter/converters configuration.
  2. Register a TypeMapping so the value maps onto a supported implementation type.
  3. Use a supported target type (List, Map, String, numbers, java.time types, etc.).

Example fix

// before
mapper.map(pklObject, MyPojo.class); // no converter
// after
mapper.registerConverter(new Converter<PklObject, MyPojo>() { ... });
mapper.map(pklObject, MyPojo.class);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!SUPPORTED_TARGETS.contains(targetType)) throw new IllegalArgumentException("register a converter for " + targetType);

Try / catch

try { return mapper.map(value, targetType); } catch (ConversionException e) { return fallbackConversion(value); }

Prevention

When it happens

Trigger: valueMapper.map(pklValue, targetType) where the Pkl value's type cannot be converted to targetType — no registered Converter, no applicable TypeMapping, and no default conversion (e.g. mapping a Pkl ListING to a custom POJO without a registered converter).

Common situations: Mapping Pkl modules to custom Java classes without registering a converter or type mapping; requesting an incompatible target (Pkl Int to java.time.Duration); typos in the target class.

Related errors


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

Appendix: source

Thrown at pkl-config-java/src/main/java/org/pkl/config/java/mapper/ValueMapperImpl.java:114

    @SuppressWarnings("unchecked")
    var implConverter = (Converter<S, T>) convertersMap.get(implKey);
    if (implConverter != null) {
      // TODO: give converter a chance to copy itself to avoid pollution of its inline caches
      convertersMap.put(key, implConverter);
      return implConverter;
    }

    // create implType converter
    for (ConverterFactory factory : factories) {
      @SuppressWarnings({"unchecked", "rawtypes"})
      Optional<Converter<S, T>> newConverter = (Optional) factory.create(sourceType, implType);
      if (newConverter.isPresent()) {
        convertersMap.put(key, newConverter.get());
        return newConverter.get();
      }
    }

    throw new ConversionException(
        String.format(
            "Cannot convert `%s` to `%s` because no conversion was found.",
            sourceType.getQualifiedName(), targetType.getTypeName()));
  }

  @Override
  public ValueMapperBuilder toBuilder() {
    return ValueMapperBuilder.unconfigured()
        .setConversions(conversions)
        .setConverterFactories(factories)
        .setTypeMappings(typeMappings);
  }
}

View on GitHub (pinned to f3efcbfc9b)