airbnb/epoxy · error · IllegalStateException
Nullability has not been set
Error message
Nullability has not been set
What it means
AttributeInfo tracks whether an Epoxy model attribute is nullable via a nullable Boolean. isNullable() is only valid after nullability has been explicitly resolved (hasSetNullability()); if processors or extensions query nullability before it was set, the annotation processor throws this IllegalStateException to prevent silently defaulting to non-null.
Solutions
- Call hasSetNullability() first and skip or defer isNullable() when false.
- Ensure the attribute builder sets nullability (setNullable or package-derived) before the attribute is used.
- If writing a processor extension, move the nullability query to a later processing step after EpoxyProcessor resolves it.
- Upgrade epoxy-processor — versions may resolve nullability earlier for your attribute kind.
Example fix
// before val nullable = attributeInfo.isNullable() // throws if unset // after val nullable = if (attributeInfo.hasSetNullability()) attributeInfo.isNullable() else false
Defensive patterns
Strategy: type-guard
Type guard
fun AttributeInfo.nullabilityOrNull(): Boolean? = if (hasSetNullability()) isNullable() else null
Prevention
- Always gate isNullable() behind hasSetNullability().
- Query nullability only in the late processing rounds, after EpoxyProcessor resolves it.
- In custom attribute builders, always set nullability before handing the AttributeInfo around.
When it happens
Trigger: A processor extension or custom validator calls attributeInfo.isNullable() before setNullable/derivation ran — e.g. reading attributes in a custom step before EpoxyProcessor's nullability resolution stage.
Common situations: Custom Epoxy annotation-processor plugins hooking into the wrong processing round; forked/patched EpoxyProcessor code paths; new attribute types added to the processor without setting nullability in the builder.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Unsupported type
- Room couldn't find the constructor it is looking for in…
- Expected this to be a variable or method $this
- Failed to create regex for resource reference…
- Please use value or code explicitly
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/158327cd75d48720.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-processor/src/main/java/com/airbnb/epoxy/processor/AttributeInfo.kt:177
var implicit: CodeBlock? = null
val isPresent: Boolean
get() = explicit != null || implicit != null
val isEmpty: Boolean
get() = !isPresent
fun value(): CodeBlock? = explicit ?: implicit
}
protected fun setJavaDocString(docComment: String?) {
javaDoc = docComment?.trim()
?.let { if (it.isNotEmpty()) CodeBlock.of(it) else null }
}
fun isNullable(): Boolean {
if (!hasSetNullability()) {
throw IllegalStateException("Nullability has not been set")
}
return isNullable == true
}
fun hasSetNullability(): Boolean = isNullable != null
fun getterCode(): String = if (isPrivate) getterMethodName!! + "()" else fieldName
// Special case to avoid generating recursive getter if field and its getter names are the same
fun superGetterCode(): String =
if (isPrivate) String.format("super.%s()", getterMethodName) else fieldName
fun setterCode(): String =
(if (isGenerated) "this." else "super.") +
if (isPrivate)
setterMethodName!! + "(\$L)"
elseView on GitHub (pinned to e45bd3a61f)