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

  1. Align the JavaPoet version with the one epoxy-processor expects (check Epoxy's build deps and force that version in your build).
  2. Upgrade epoxy-processor to a release compatible with your JavaPoet version.
  3. Inspect the wrapped cause (ex) to see which constructor signature was expected vs available.
  4. 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

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


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)