apple/pkl · error · ConversionException

Expected a non-null value but got `null`. To allow null…

Error message

Expected a non-null value but got `null`. To allow null values, convert to a nullable Kotlin type, for example `String?`.

What it means

Config.to<T>() converts a Pkl Config value into a Kotlin type T. This error means the Pkl value is null but the requested Kotlin type T is non-nullable, so the conversion cannot proceed. The library deliberately tells you the fix: make T nullable (e.g. String?) to accept null.

Solutions

  1. Make the target Kotlin type nullable: config.to<String?>() instead of config.to<String>().
  2. If the field should never be null, fix the Pkl config/amendment so the property has a value.
  3. Provide a default before conversion: config["prop"]?.let { it.to<String>() } ?: fallback (check null on the Config view first).

Example fix

// before
val name: String = config.to<String>()
// after
val name: String? = config.to<String?>()
Defensive patterns

Strategy: type-guard

Validate before calling

if (config["name"] == null) error("config.name is null; provide a value or use String?")

Type guard

inline fun <reified T> Config.toOrNull(): T? =
  if (null is T) asNullable(typeOf<T>().javaType) else `as`(typeOf<T>().javaType)

Try / catch

val name = try {
  config.to<String>()
} catch (e: ConversionException) {
  null // or default value
}

Prevention

When it happens

Trigger: Calling config.to<String>() (or to<Foo>()) where the underlying Pkl property's value is null (e.g. `foo: String?` in Pkl set to null, or an амended property nulling it).

Common situations: Pkl schema allows a nullable field that is left null; an amendment sets a field to null; caller assumes required fields and uses non-nullable Kotlin types.

Related errors


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

Appendix: source

Thrown at pkl-config-kotlin/src/main/kotlin/org/pkl/config/kotlin/ConfigExtensions.kt:48

/**
 * Converts this [Config] node to type [T] using the configured
 * [org.pkl.config.java.mapper.ValueMapper].
 *
 * To allow `null` values, specify a nullable type, for example `to<String?>()`.
 *
 * Kotlin code should prefer this method over [Config.as] for the following reasons:
 * * does not clash with Kotlin's `as` keyword
 * * throws [ConversionException] if conversion to non-nullable type returns `null`
 * * easier to use with parameterized types: `to<List<String>>()` vs.
 *   `as(JavaType.listOf(String::class.java))`
 */
inline fun <reified T> Config.to(): T {
  if (null is T) {
    return asNullable(typeOf<T>().javaType)
  }

  return `as`(typeOf<T>().javaType)
    ?: throw ConversionException(
      "Expected a non-null value but got `null`. " +
        "To allow null values, convert to a nullable Kotlin type, for example `String?`."
    )
}

/**
 * Configures this [ValueMapperBuilder] with conversions and converter factories for Kotlin types.
 */
fun ValueMapperBuilder.forKotlin(): ValueMapperBuilder =
  addConversions(KotlinConversions.all).addConverterFactories(KotlinConverterFactories.all)

/**
 * Configures this [ConfigEvaluatorBuilder] with conversions and converter factories for Kotlin
 * types.
 */
fun ConfigEvaluatorBuilder.forKotlin(): ConfigEvaluatorBuilder =
  setValueMapperBuilder(valueMapperBuilder.forKotlin())

View on GitHub (pinned to f3efcbfc9b)