Debugging log · Kotlin
"Inferred type is String? but String was expected"
Kotlin stopped my build over a value I was sure held text: inferred type is String? but String was expected. The frustrating first reaction is "but it clearly has a value" — and that's exactly the point Kotlin is making. It doesn't care what the value happens to be at runtime; it cares that the type allows null, and you're using it somewhere null isn't permitted.
The short version: the trailing ? means "might be null". You're passing a String? where a non-null String is required. Fix it by proving it's not null (a check, ?:, or let) rather than forcing it with !!.
What the ? actually means
In Kotlin, String and String? are different types. String can never be null; String? might be. This is the whole point of Kotlin's null safety: the compiler tracks nullability in the type system so a NullPointerException becomes a compile error instead of a crash. The message isn't a bug in your code — it's the safety net catching a place where a possibly-null value would flow into code that can't handle null.
Where the ? sneaks in
- Platform types from Java. A Java method with no nullability annotation returns a type Kotlin treats cautiously — often inferred as nullable.
- Nullable map/collection lookups.
map[key]returnsV?because the key might be absent. - findViewById, intent extras, arguments. Many Android APIs return nullable by design.
- A property declared
var name: String?that you later use where non-null is required.
Fix 1 — the Elvis operator (a sensible default)
Provide a fallback for the null case with ?::
val name: String = maybeName ?: "Unknown"
Now the result is a non-null String: the real value if present, the fallback if null. This is usually the cleanest fix when a reasonable default exists.
Fix 2 — check, then use
If you only want to act when the value is present, a null check narrows the type inside the block:
val n = maybeName
if (n != null) {
// n is smart-cast to non-null String here
greet(n)
}
// or scope it with let:
maybeName?.let { greet(it) }
Kotlin's smart casts mean that after you've checked for null, it treats the value as non-null within that scope — no extra syntax needed.
Fix 3 — fix the source's nullability
Sometimes the right fix is upstream. If a property never should be null, declare it non-null (val name: String) and initialize it properly, rather than declaring it nullable and fighting the ? at every use. Making the type honest removes the error everywhere at once.
Resist !!. The double-bang asserts "this is never null, trust me" and turns the compile error back into a runtime crash the moment you're wrong. It's occasionally justified, but reaching for it to silence this message trades a safe compile-time signal for an unsafe runtime one. Prefer ?:, a check, or fixing the type.
Quick decision guide
- Have a sensible default? Use
?:. - Only act when present? Use a null check or
?.let { }. - Should never be null? Fix the declaration or the Java annotation upstream.
- Absolutely certain it's non-null here?
!!exists — but treat it as a last resort you can justify, not a reflex.
Variable and value names above are illustrative — apply the pattern to your own code.