skip to content

What happens if you read a `lateinit var` before it is assigned, and what exception is thrown?

level: middleimportance: must knowfreq 65%

answer

  1. UninitializedPropertyAccessException
  2. Message names the property
  3. Unchecked / RuntimeException
  4. Not a plain NPE
  5. Prefer isInitialized over try/catch

basics

~10 s

Reading it before you set it throws an error called UninitializedPropertyAccessException. The message tells you which property wasn't initialized.

solid answer

~40 s

Each read of a `lateinit` property goes through a compiler-generated check. If the backing field is still its internal null sentinel, the read throws `kotlin.UninitializedPropertyAccessException` with a message like `lateinit property repository has not been initialized`. This is distinct from `NullPointerException`: the type is non-null, so there's no `?.`/`!!`, but the guard exists at runtime. The exception is unchecked (extends `RuntimeException`) and signals a programming/lifecycle bug — a property was read before its setup phase ran (missing `@BeforeEach`, DI not wired, accessed before `onCreate`). You generally fix the lifecycle rather than catch it; to defensively check, use `if (::repository.isInitialized)` (covered separately) instead of try/catch.

code

kotlin · 10 lines
kotlin
class Service {
    lateinit var client: HttpClient
}

val s = Service()
try {
    s.client.toString()
} catch (e: UninitializedPropertyAccessException) {
    println(e.message) // lateinit property client has not been initialized
}

go deeper

for a junior

Knows reading before assignment throws an exception rather than returning null.

for a middle

Names UninitializedPropertyAccessException, knows the message identifies the property, and that it's not a plain NPE.

for a senior

Explains it's an unchecked RuntimeException signaling a lifecycle bug and prefers isInitialized guards over try/catch.

for a principal

Connects it to DI/test/Android lifecycle pitfalls and sets guidance on diagnosing vs defensively guarding across the codebase.

## The runtime guard For every read of a `lateinit` property, the Kotlin compiler emits a check equivalent to: "if the backing field is the uninitialized sentinel, throw." The thrown type is: ``` kotlin.UninitializedPropertyAccessException ``` with a descriptive message, e.g.: ``` lateinit property repository has not been initialized ``` ## How it differs from NullPointerException - The declared type is **non-null**, so the compiler does not force `?.` or `!!` at call sites. - Instead of an NPE on a method call, you get a **specific, named** exception that immediately tells you *which* property and *that* it was never assigned — far more diagnostic than a bare NPE. ```kotlin class Repo { lateinit var dataSource: DataSource fun query() = dataSource.toString() } val r = Repo() r.query() // kotlin.UninitializedPropertyAccessException: lateinit property dataSource has not been initialized ``` ## Exception characteristics - It **extends `RuntimeException`**, so it is unchecked — no `throws` clause, no forced handling. - It indicates a **lifecycle/wiring bug**, not a recoverable condition. The right fix is usually ensuring the assignment runs first (wire DI correctly, add `@BeforeEach`, assign in `onCreate`). ## How to avoid it 1. **Guarantee assignment** before any read in the object's lifecycle. 2. **Check first** with the backing-reference syntax: ```kotlin if (::dataSource.isInitialized) { dataSource.query() } ``` Using `::dataSource.isInitialized` is the idiomatic, cheap check — prefer it over wrapping reads in `try/catch (e: UninitializedPropertyAccessException)`, which is slow and hides design problems. (The `isInitialized` mechanics are detailed in a sibling topic.) ## Common real-world triggers - A Spring `@Autowired lateinit var` read before the context finished wiring (e.g., in a field initializer of the same bean). - A test reading a fixture before `@BeforeEach` set it, or after a `@BeforeEach` that threw. - Android: touching a `lateinit` view before `onCreate`/`onViewCreated`.

  • Is `UninitializedPropertyAccessException` checked or unchecked?
    Unchecked — it extends `RuntimeException`, so the compiler doesn't force you to declare or catch it.
  • Should you catch this exception in production code?
    Rarely. It signals a lifecycle bug. Prefer guaranteeing assignment or guarding with `::prop.isInitialized` rather than catching, which masks the real problem and is costly.

saying these in an interview costs you the question

  • Saying early access returns null
  • Claiming it throws a NullPointerException
  • Thinking the exception is checked
  • Recommending try/catch as the normal pattern
  • Not knowing the exception message names the property

context