airbnb/epoxy · critical · RuntimeException
Unable to get Epoxy helper class.
Error message
Unable to get Epoxy helper class.
What it means
When the reflective helper creation fails with InvocationTargetException whose cause is neither RuntimeException nor Error, the library wraps the cause in RuntimeException('Unable to get Epoxy helper class.'). This means the generated helper's constructor ran and threw a checked/other throwable.
Solutions
- Read the cause chain (RuntimeException.getCause()) to find the original throwable thrown inside the helper constructor.
- Fix the throwing initializer in the controller so construction cannot fail.
- Align epoxy-compiler, epoxy-adapter, and epoxy-processor versions.
- Clean/rebuild to regenerate helpers after moving or renaming controllers.
Example fix
// before
class MyController extends EpoxyController {
private final Config cfg = loadConfigChecked(); // throws checked exception
}
// after
class MyController extends EpoxyController {
private final Config cfg;
MyController() { this.cfg = loadConfigSafely(); } // no throwing initializer
} Defensive patterns
Strategy: try-catch
Validate before calling
// audit controller field initializers for code that can throw during construction
Try / catch
try { helper = ControllerHelperLookup.getHelperForController(controller); } catch (RuntimeException e) { Throwable cause = e.getCause(); log("Helper ctor threw", cause); } Prevention
- Keep controller constructors and field initializers exception-free.
- Align all epoxy artifact versions.
- Clean rebuild after moving/renaming controllers.
When it happens
Trigger: The generated _EpoxyHelper constructor for a controller throws a checked exception (e.g. Exception from an initializer block or field initialization in the controller/helper) that is not a RuntimeException or Error.
Common situations: Controller field initializers or constructor-time code throwing checked exceptions; classpath conflicts causing NoClassDefFoundError-like checked paths; mismatched epoxy-compiler and epoxy-adapter versions producing broken generated code.
Related errors
- Unable to invoke
- Unable to find Epoxy Helper constructor for
- Failed to hijack update handler in AsyncPagedListDiffer.You…
- Room couldn't find the constructor it is looking for in…
- Must have stable ids when saving view holder state
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/7bf76c703ce8c7ee.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/ControllerHelperLookup.java:40
if (constructor == null) {
return NO_OP_CONTROLLER_HELPER;
}
try {
return (ControllerHelper) constructor.newInstance(controller);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to invoke " + constructor, e);
} catch (InstantiationException e) {
throw new RuntimeException("Unable to invoke " + constructor, e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException("Unable to get Epoxy helper class.", cause);
}
}
@Nullable
private static Constructor<?> findConstructorForClass(Class<?> controllerClass) {
Constructor<?> helperCtor = BINDINGS.get(controllerClass);
if (helperCtor != null || BINDINGS.containsKey(controllerClass)) {
return helperCtor;
}
String clsName = controllerClass.getName();
if (clsName.startsWith("android.") || clsName.startsWith("java.")) {
return null;
}
try {
Class<?> bindingClass = Class.forName(clsName + GENERATED_HELPER_CLASS_SUFFIX);
//noinspection uncheckedView on GitHub (pinned to e45bd3a61f)