Real examples of type errors in Kotlin: examples and fixes

If you write Kotlin long enough, you’ll hit type errors. Some are obvious, others show up as cryptic compiler messages right when you think the code is finally ready. This guide walks through real, concrete examples of type errors in Kotlin: examples and fixes that mirror what developers actually see in day‑to‑day Android and backend work. Instead of abstract theory, we’ll focus on how the Kotlin type system pushes you toward safer code, and what to do when it pushes back. You’ll see how mismatched generics, nullable vs non‑nullable types, smart casts, variance, and platform types all trigger different flavors of type mismatch. For each example, we’ll look at the compiler message, the broken code, and a clean, idiomatic Kotlin fix. By the end, you’ll not only recognize the most common examples of type errors in Kotlin, you’ll also have a mental checklist for debugging new ones quickly on your own.
Written by
Jamie
Published
Updated

Kotlin’s type system is strict on purpose. It prevents whole classes of runtime bugs, but that safety shows up as compile‑time type errors. Let’s walk through some of the best examples of type errors in Kotlin, along with fixes you can actually reuse.

You’ll see that most compiler messages fall into patterns:

  • Type mismatch between expected and actual type
  • Nullability conflicts (T vs T?)
  • Smart cast not allowed
  • Generic type mismatch
  • Variance (in / out) issues
  • Platform type surprises from Java interop

Each section below contains at least one real example of a type error, the message you’re likely to see, and a practical fix.


Example 1: Classic Type mismatch between Int and Long

This is one of the simplest examples of type errors in Kotlin, but it still bites people migrating from Java.

fun totalUsers(): Long {
    val active: Int = 120
    val inactive: Int = 5

    // Type mismatch: inferred type is Int but Long was expected
    return active + inactive
}

The compiler sees active + inactive as an Int, but the function promises to return a Long.

Fix options:

You can either change the function return type to Int or promote the expression to Long.

fun totalUsers(): Long {
    val active = 120
    val inactive = 5
    return (active + inactive).toLong()
}

Or, if you’re working with large counts and really want Long everywhere:

fun totalUsers(): Long {
    val active: Long = 120L
    val inactive: Long = 5L
    return active + inactive
}

The pattern: whenever you see a simple Type mismatch error, compare the function signature, variable types, and literal suffixes (L for Long, f for Float).


Example 2: Nullability mismatch – assigning String? to String

Kotlin’s null‑safety is one of its biggest selling points and one of the most common sources of type errors.

fun greet(name: String?) {
    // Type mismatch: inferred type is String? but String was expected
    val upper: String = name.uppercase()
    println("Hello, $upper")
}

The compiler is yelling because name is String?, so name.uppercase() is also String?. You’re trying to assign that to a non‑nullable String.

Better fix: handle the null case explicitly.

fun greet(name: String?) {
    val upper: String = name?.uppercase() ?: "ANONYMOUS"
    println("Hello, $upper")
}

Or, if you want to fail fast instead of defaulting:

fun greet(name: String?) {
    val upper: String = name?.uppercase()
        ?: error("Name must not be null")
    println("Hello, $upper")
}

If you’re absolutely certain it can’t be null at this point, you can use !!:

val upper: String = name!!.uppercase()

…but that turns a compile‑time type error into a potential runtime NullPointerException. Use it sparingly.

This is one of the best examples of type errors in Kotlin: examples and fixes that clearly show how the type system forces you to think about nulls.


Example 3: Smart cast error – variable can be changed by another thread

Smart casts are Kotlin’s way of letting you write code that feels dynamic but is still statically checked. They don’t always work, though.

fun printLength(text: CharSequence?) {
    if (text is String) {
        // Smart cast to 'String' is impossible, because 'text' is a mutable property that could be changed by another thread
        println(text.length)
    }
}

You’ll see this sort of error when:

  • The variable is not val
  • Or it’s a property with a custom getter
  • Or it’s captured from a closure where the compiler can’t prove it won’t change

Fix: create a local val inside the if block.

fun printLength(text: CharSequence?) {
    if (text is String) {
        val s: String = text
        println(s.length)
    }
}

Or use when with a smart cast‑friendly pattern:

fun printLength(text: CharSequence?) {
    when (text) {
        is String -> println(text.length)
        null -> println("No text")
        else -> println("Not a String")
    }
}

This kind of smart cast issue is a subtle example of a type error in Kotlin that shows up more often in concurrent or Android UI code.


Example 4: Generic type mismatch – List<String> vs List<Any>

Generics are where many of the trickier examples of type errors in Kotlin live.

fun addItem(target: MutableList<Any>) {
    target.add(42)
}

fun main() {
    val names: MutableList<String> = mutableListOf("Alice", "Bob")

    // Type mismatch: inferred type is MutableList<String> but MutableList<Any> was expected
    addItem(names)
}

In Java, this might compile thanks to raw types (and then blow up later). Kotlin’s type system doesn’t allow passing MutableList<String> where MutableList<Any> is expected.

Why? If it were allowed, addItem could insert an Int into a list of String, breaking type safety.

Fix options:

  • Change the function to be generic:
fun <T> addItem(target: MutableList<T>, item: T) {
    target.add(item)
}

fun main() {
    val names = mutableListOf("Alice", "Bob")
    addItem(names, "Carol")
}
  • Or narrow the parameter type to what you actually need:
fun addName(target: MutableList<String>, name: String) {
    target.add(name)
}

This is a textbook example of type errors in Kotlin: examples and fixes that come directly from Kotlin’s stricter generics compared to Java.


Example 5: Variance (out / in) and Type mismatch

Variance annotations (out, in) are another source of confusing compiler messages.

class Box<out T>(val value: T)

fun takeAnyBox(box: Box<Any>) { /* ... */ }

fun main() {
    val stringBox: Box<String> = Box("Hello")

    // Type mismatch: inferred type is Box<String> but Box<Any> was expected
    takeAnyBox(stringBox)
}

You’d expect Box<String> to be usable where Box<Any> is expected, because String is a subtype of Any. But Kotlin doesn’t automatically infer the variance here.

Fix: use a covariant type parameter in the function instead of Box<Any>.

fun takeAnyBox(box: Box<*>) { /* read‑only */ }

// or

fun <T> takeAnyBox(box: Box<T>) { /* read‑only */ }

If you only read from box, use a star projection (Box<*>) or a covariant out parameter on the class as we did. If you need to both read and write, you probably want in on the parameter type instead.

Kotlin’s official docs have a solid explanation of variance with more examples: https://kotlinlang.org/docs/generics.html


Example 6: Platform types and Java interop surprises

When you call Java code from Kotlin, you get platform types – types where the nullability isn’t known at compile time. This is one of the more subtle real examples of type errors in Kotlin.

Imagine a Java API:

// Java
public class UserApi {
    public String getUsername() { return null; }
}

From Kotlin:

val api = UserApi()

// 'username' is a platform type: String! (unknown nullability)
val username: String = api.username
// This may compile but can crash at runtime with NPE

The compiler allows this assignment, but it’s not actually safe. When you start adding nullability annotations in Java (@Nullable, @NotNull), Kotlin’s type system gets better information and you see more explicit type errors instead of runtime crashes.

Better pattern in Kotlin:

val username: String? = api.username
val safeUsername: String = username ?: "guest"

Or, if you control the Java code, annotate it with something like org.jetbrains.annotations.NotNull or @Nullable so Kotlin can infer the right type and give you real compile‑time errors.

For background on nullability annotations and static analysis, the U.S. National Institute of Standards and Technology (NIST) has general guidance on safer software practices: https://samate.nist.gov/


Example 7: Nothing and non‑returning functions

Nothing is Kotlin’s bottom type. It represents a value that never exists because the function never returns.

fun fail(message: String): Nothing {
    throw IllegalStateException(message)
}

fun computeOrFail(flag: Boolean): Int {
    if (!flag) {
        // Works: fail() returns Nothing, which is a subtype of Int
        return fail("Flag must be true")
    }

    // Type mismatch: inferred type is Nothing but Int was expected
    return fail("Unreachable")
}

The first return fail(...) is fine, because Nothing can stand in for any type. The second one is misleading: the function already returns from the fail call, so the compiler may complain depending on control‑flow analysis.

Cleaner fix: just call fail without return when it’s the last statement.

fun computeOrFail(flag: Boolean): Int {
    if (!flag) fail("Flag must be true")

    // ... compute result
    return 42
}

You’ll occasionally see Nothing in more advanced APIs (like error() or TODO()), and understanding it helps interpret some of the stranger type error messages.


Example 8: Lambda type mismatch – function type vs value type

Lambdas are another common source of examples of type errors in Kotlin.

fun <T> applyTwice(value: T, f: (T) -> T): T = f(f(value))

fun main() {
    val x: Int = 10

    // Type mismatch: inferred type is Int but (Int) -> Int was expected
    applyTwice(x, x + 1)
}

The second argument should be a function from Int to Int, but x + 1 is just an Int value.

Fix: pass a lambda or function reference instead.

applyTwice(x) { it + 1 }

// or

fun increment(i: Int): Int = i + 1
applyTwice(x, ::increment)

Any time you see a type error where the compiler expected something like (A) -> B, check whether you accidentally passed a value instead of a function.


Kotlin keeps tightening its type system as the language matures. Recent compiler versions (including K2, the new frontend) are better at:

  • Detecting incorrect nullability assumptions
  • Inferring generic types
  • Reporting clearer error messages

With Kotlin now a first‑class language for Android, server‑side development, and even data science, understanding these examples of type errors in Kotlin: examples and fixes is a real productivity boost. You’ll spend less time fighting the compiler and more time shipping code that doesn’t crash.

If you want to go deeper on static typing benefits in general, Harvard’s CS courses have accessible material on type systems and safety guarantees: https://cs50.harvard.edu/


FAQ: common questions about examples of type errors in Kotlin

What are the most common examples of type errors in Kotlin for beginners?

The most common examples include:

  • Assigning String? to String without handling null
  • Returning Int from a function declared to return Long
  • Passing MutableList<String> where MutableList<Any> is expected
  • Forgetting that a lambda parameter expects a function type, not a value

If you’re new, pay extra attention to nullability and generics; most early type mismatch issues show up there.

Can I just disable strict type checks in Kotlin?

No. Kotlin is statically typed by design. You can loosen some checks with casts (as Any, as?) or by using platform types from Java, but that just moves the problem to runtime. The whole point of learning from these real examples of type errors in Kotlin is to fix the underlying type problems, not silence the compiler.

Is there a simple example of turning a runtime crash into a compile‑time type error?

A classic example is handling nulls coming from Java APIs. In Java, you might see a surprise NullPointerException when a method returns null. In Kotlin, if you declare the type as String? and then try to use it as String without a null check, the compiler gives you a type error instead of letting the crash reach production.

How can I get better at reading Kotlin type error messages?

Treat the message as a diff between expected and found types. Read it left to right:

  • “Required: List<String>
  • “Found: List<Any>

Then ask: where did the expected type come from (function signature, variable declaration), and where did the found type come from (expression, literal, generic inference)? Once you train that habit on a few examples of type errors in Kotlin, your debugging speed goes way up.

Where can I learn more about Kotlin’s type system?

The official Kotlin documentation is the best starting point:

  • Kotlin types overview: https://kotlinlang.org/docs/basic-types.html
  • Null safety: https://kotlinlang.org/docs/null-safety.html
  • Generics and variance: https://kotlinlang.org/docs/generics.html

While not Kotlin‑specific, general software safety resources from organizations like NIST (https://samate.nist.gov/) and university CS departments (for example, Harvard’s CS courses at https://cs50.harvard.edu/) help build the mental model behind why strong type systems catch bugs early.


By working through these real examples of type errors in Kotlin: examples and fixes, you’ll start to recognize patterns in the compiler’s complaints. Once you see those patterns, type errors stop feeling like random roadblocks and start acting like a very opinionated, very fast code reviewer that keeps your app from shipping with avoidable bugs.

Explore More Type Errors

Discover more examples and insights in this category.

View All Type Errors