airbnb/epoxy · critical · RuntimeException

Unable to find Epoxy Helper constructor for

Error message

Unable to find Epoxy Helper constructor for {clsName}

What it means

findConstructorForClass loads <ClassName>_EpoxyHelper reflectively and gets its constructor taking the controller class. If the class exists but has no matching constructor (NoSuchMethodException), it throws RuntimeException('Unable to find Epoxy Helper constructor for <clsName>'). Note a missing class (ClassNotFoundException) instead walks up the superclass hierarchy.

Solutions

  1. Clean build to regenerate helper classes so signatures match controllers.
  2. Verify epoxy-compiler version matches epoxy-adapter across all modules.
  3. Rename or remove any hand-written class colliding with the <Controller>_EpoxyHelper name.
  4. Confirm the controller class wasn't renamed after generation; regenerate.

Example fix

// before
// stale generated MyController_EpoxyHelper with no (MyController) ctor

// after
// clean rebuild:
./gradlew clean :app:build // regenerates MyController_EpoxyHelper(MyController)
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check generated class presence:
Class.forName(clsName + "_EpoxyHelper").getConstructor(controllerClass);

Try / catch

try { ... } catch (RuntimeException e) { if (e.getMessage().startsWith("Unable to find Epoxy Helper constructor")) { /* regenerate code / fix build */ throw e; } }

Prevention

When it happens

Trigger: The generated <Class>_EpoxyHelper class exists but its constructor signature doesn't take the controller class — typically from stale generated code, a hand-written class name collision, or generated code from a different controller version.

Common situations: Partial incremental builds after renaming a controller; mixing epoxy-compiler versions across modules; a user class accidentally named <Controller>_EpoxyHelper shadowing generated code.

Related errors


AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13). Data as JSON: /api/errors/285a03ea6a2a7140. Report an issue: GitHub.

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/ControllerHelperLookup.java:63

  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 unchecked
      helperCtor = bindingClass.getConstructor(controllerClass);
    } catch (ClassNotFoundException e) {
      helperCtor = findConstructorForClass(controllerClass.getSuperclass());
    } catch (NoSuchMethodException e) {
      throw new RuntimeException("Unable to find Epoxy Helper constructor for " + clsName, e);
    }
    BINDINGS.put(controllerClass, helperCtor);
    return helperCtor;
  }
}

View on GitHub (pinned to e45bd3a61f)