What happens if you read a `lateinit var` before it is assigned, and what exception is thrown?
answer
- UninitializedPropertyAccessException
- Message names the property
- Unchecked / RuntimeException
- Not a plain NPE
- Prefer isInitialized over try/catch
basics
~10 sReading it before you set it throws an error called UninitializedPropertyAccessException. The message tells you which property wasn't initialized.
solid answer
~40 sEach 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 linesclass 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
Knows reading before assignment throws an exception rather than returning null.
Names UninitializedPropertyAccessException, knows the message identifies the property, and that it's not a plain NPE.
Explains it's an unchecked RuntimeException signaling a lifecycle bug and prefers isInitialized guards over try/catch.
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