airbnb/epoxy · critical · IllegalStateException
Room couldn't find the constructor it is looking for in…
Error message
Room couldn't find the constructor it is looking for in JavaPoet. Please file a bug.
What it means
TypeNameWorkaround works around JavaPoet/Room type-name interop by reflectively accessing a JavaPoet constructor (matched against String/List class signatures). The reflective lookup happens in a static initializer; if the expected constructor does not exist in the bundled JavaPoet version, NoSuchMethodException is wrapped and rethrown as this IllegalStateException, meaning the workaround is broken for this JavaPoet version.
Solutions
- Align the JavaPoet version with the one epoxy-processor expects (check Epoxy's build deps and force that version in your build).
- Upgrade epoxy-processor to a release compatible with your JavaPoet version.
- Inspect the wrapped cause (ex) to see which constructor signature was expected vs available.
- As a stopgap, exclude transitive JavaPoet upgrades with a resolutionStrategy force on the known-good version.
Example fix
// before (build.gradle.kts)
implementation("com.squareup:javapoet:1.14.0") // newer, incompatible
// after
implementation("com.squareup:javapoet:1.13.0") // version epoxy-processor expects Defensive patterns
Strategy: try-catch
Validate before calling
// build-time guard: fail fast on JavaPoet drift
try {
Class.forName("com.airbnb.epoxy.processor.TypeNameWorkaround")
.declaredMethods // triggers init
} catch (e: ExceptionInInitializerError) {
throw IllegalStateException("JavaPoet version incompatible with epoxy-processor", e)
} Try / catch
try {
runAnnotationProcessing()
} catch (e: IllegalStateException) {
if (e.message?.contains("Room couldn't find the constructor") == true) {
error("Fix JavaPoet version: ${e.cause?.cause}")
} else throw e
} Prevention
- Pin the exact JavaPoet version epoxy-processor was built against.
- Upgrade epoxy-processor in lockstep with JavaPoet.
- Add a resolutionStrategy force on JavaPoet to block transitive upgrades.
- Read the wrapped NoSuchMethodException cause to identify the changed constructor.
When it happens
Trigger: Any annotation-processing run where epoxy-processor is paired with an incompatible JavaPoet version whose internal constructor signatures changed — the class init fails immediately at processor startup.
Common situations: Upgrading JavaPoet (or a dependency pulling a newer JavaPoet) without upgrading epoxy-processor; dependency-resolution choosing a different JavaPoet than the one Epoxy was built against; using a forked JavaPoet.
Related errors
- Unsupported type
- Unable to invoke
- Unable to get Epoxy helper class.
- Unable to find Epoxy Helper constructor for
- Failed to hijack update handler in AsyncPagedListDiffer.You…
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/6035d99d7fd75216.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-processor/src/main/java/com/airbnb/epoxy/processor/TypeNameWorkaround.kt:346
}
}
}
/**
* The private constructor of [TypeVariableName] which receives a list.
* We use this in [createModifiableTypeVariableName] to create a [TypeVariableName] whose bounds
* can be modified afterwards.
*/
private val typeVarNameConstructor by lazy {
try {
TypeVariableName::class.java.getDeclaredConstructor(
String::class.java,
List::class.java
).also {
it.isAccessible = true
}
} catch (ex: NoSuchMethodException) {
throw IllegalStateException(
"""
Room couldn't find the constructor it is looking for in JavaPoet.
Please file a bug.
""".trimIndent(),
ex
)
}
}
/**
* Creates a TypeVariableName where we can change the bounds after constructor.
* This is used to workaround a case for self referencing type declarations.
* see b/187572913 for more details
*/
private fun createModifiableTypeVariableName(
name: String,
bounds: List<TypeName>
): TypeVariableName = typeVarNameConstructor.newInstance(View on GitHub (pinned to e45bd3a61f)