{"record":{"id":"285a03ea6a2a7140","repo":"airbnb/epoxy","slug":"unable-to-find-epoxy-helper-constructor-for-clsname","errorCode":null,"errorMessage":"Unable to find Epoxy Helper constructor for {clsName}","messagePattern":"Unable to find Epoxy Helper constructor for (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/ControllerHelperLookup.java","lineNumber":63,"sourceCode":"  private static Constructor<?> findConstructorForClass(Class<?> controllerClass) {\n    Constructor<?> helperCtor = BINDINGS.get(controllerClass);\n    if (helperCtor != null || BINDINGS.containsKey(controllerClass)) {\n      return helperCtor;\n    }\n\n    String clsName = controllerClass.getName();\n    if (clsName.startsWith(\"android.\") || clsName.startsWith(\"java.\")) {\n      return null;\n    }\n\n    try {\n      Class<?> bindingClass = Class.forName(clsName + GENERATED_HELPER_CLASS_SUFFIX);\n      //noinspection unchecked\n      helperCtor = bindingClass.getConstructor(controllerClass);\n    } catch (ClassNotFoundException e) {\n      helperCtor = findConstructorForClass(controllerClass.getSuperclass());\n    } catch (NoSuchMethodException e) {\n      throw new RuntimeException(\"Unable to find Epoxy Helper constructor for \" + clsName, e);\n    }\n    BINDINGS.put(controllerClass, helperCtor);\n    return helperCtor;\n  }\n}\n","sourceCodeStart":45,"sourceCodeEnd":69,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/ControllerHelperLookup.java#L45-L69","documentation":"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.","triggerScenarios":"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.","commonSituations":"Partial incremental builds after renaming a controller; mixing epoxy-compiler versions across modules; a user class accidentally named <Controller>_EpoxyHelper shadowing generated code.","solutions":["Clean build to regenerate helper classes so signatures match controllers.","Verify epoxy-compiler version matches epoxy-adapter across all modules.","Rename or remove any hand-written class colliding with the <Controller>_EpoxyHelper name.","Confirm the controller class wasn't renamed after generation; regenerate."],"exampleFix":"// before\n// stale generated MyController_EpoxyHelper with no (MyController) ctor\n\n// after\n// clean rebuild:\n./gradlew clean :app:build // regenerates MyController_EpoxyHelper(MyController)","handlingStrategy":"try-catch","validationCode":"// pre-check generated class presence:\nClass.forName(clsName + \"_EpoxyHelper\").getConstructor(controllerClass);","typeGuard":null,"tryCatchPattern":"try { ... } catch (RuntimeException e) { if (e.getMessage().startsWith(\"Unable to find Epoxy Helper constructor\")) { /* regenerate code / fix build */ throw e; } }","preventionTips":["Run clean builds after renaming controllers.","Avoid naming your own classes *_EpoxyHelper.","Keep epoxy-compiler versions consistent across modules.","Verify annotation processing is enabled in the IDE/build."],"tags":["android","epoxy","reflection","code-generation","stale-build"],"backgroundTag":"class-not-found","analyzedSha":"e45bd3a61fe3a1f130e184f5b8dcf172ab99025a","analyzedAt":"2026-09-13T03:24:16.052Z","contentChangedAt":"2026-09-13T03:24:16.052Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}