JakeWharton/butterknife · error · RuntimeException
Unable to find binding constructor for {}
Error message
Unable to find binding constructor for {} What it means
ButterKnife loaded the generated class Foo_ViewBinding via reflection, but Class.getConstructor(Foo.class, View.class) threw NoSuchMethodException — the generated class exists yet does not expose the expected (TargetType, View) constructor. This is a structural mismatch between the butterknife runtime's expectations and the actually generated code, most commonly caused by mixing incompatible versions of the butterknife-compiler (annotation processor) and the butterknife runtime library.
Source
Thrown at butterknife/src/main/java/butterknife/ButterKnife.java:209
if (debug) Log.d(TAG, "HIT: Cached in binding map.");
return bindingCtor;
}
String clsName = cls.getName();
if (clsName.startsWith("android.") || clsName.startsWith("java.")
|| clsName.startsWith("androidx.")) {
if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
return null;
}
try {
Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");
//noinspection unchecked
bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
if (debug) Log.d(TAG, "HIT: Loaded binding class and constructor.");
} catch (ClassNotFoundException e) {
if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());
bindingCtor = findBindingConstructorForClass(cls.getSuperclass());
} catch (NoSuchMethodException e) {
throw new RuntimeException("Unable to find binding constructor for " + clsName, e);
}
BINDINGS.put(cls, bindingCtor);
return bindingCtor;
}
}
View on GitHub (pinned to fcdebedf32)
Solutions
- Pin butterknife and butterknife-compiler (and butterknife-gradle-plugin if used) to the exact same version in build.gradle, then clean build.
- Run ./gradlew app:dependencies --configuration releaseRuntimeClasspath (and debug) to find a transitive ButterKnife version overriding yours; force alignment with a resolutionStrategy or BOM.
- Add the official ProGuard keep rules (-keep class **_ViewBinding { <init>(...); }) so R8 does not strip or alter the generated constructor.
- If mismatch persists, inspect app/build/generated/source/apt(或kapt)/.../Foo_ViewBinding.java to see the actual constructor signature and confirm which processor version generated it.
Example fix
// before: version skew produces Foo_ViewBinding without (Foo, View) ctor // java.lang.RuntimeException: Unable to find binding constructor for com.example.Foo implementation 'com.jakewharton:butterknife:10.2.3' annotationProcessor 'com.jakewharton:butterknife-compiler:9.0.0' // stale! // after: aligned versions + clean build implementation 'com.jakewharton:butterknife:10.2.3' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' // then: ./gradlew clean assembleDebug
Defensive patterns
Strategy: validation
Validate before calling
// Before bind, confirm the generated class has the exact (Target, View) constructor
public static boolean hasValidBindingConstructor(Class<?> targetClass) {
String name = targetClass.getName();
if (name.startsWith("android.") || name.startsWith("java.") || name.startsWith("androidx.")) {
return true; // framework classes: bind() returns Unbinder.EMPTY, no error
}
try {
Class<?> bindingClass = targetClass.getClassLoader().loadClass(name + "_ViewBinding");
bindingClass.getConstructor(targetClass, View.class);
return true;
} catch (NoSuchMethodException e) {
return false; // version-skewed or altered generated code
} catch (ClassNotFoundException e) {
return true; // no generated class: bind() falls back to superclass/EMPTY
}
} Try / catch
try {
unbinder = ButterKnife.bind(this);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Unable to find binding constructor")) {
// structural mismatch: generated class exists but ctor signature differs ->
// almost always butterknife compiler/runtime version skew
throw new IllegalStateException("ButterKnife version mismatch: align butterknife and butterknife-compiler", e);
}
throw e;
} Prevention
- Align butterknife runtime and compiler versions in every module; use a version catalog or BOM to enforce it.
- Review ./gradlew dependencies output after library updates for transitive ButterKnife versions.
- Keep **_ViewBinding classes and constructors in ProGuard/R8 rules when minification is on.
- Migrate to View Binding when possible — it is compile-time and immune to reflection/ProGuard mismatch failures.
When it happens
Trigger: Calling any ButterKnife.bind(...) overload on a class Foo for which Foo_ViewBinding is on the classpath but its constructor signature is not exactly (Foo, View) — e.g. generated by a different (older/newer) ButterKnife version whose constructor takes (Foo, View, Unbinder) or uses a different parameter list, or the generated class was modified/obfuscated so the constructor was renamed or its parameter types changed.
Common situations: Upgrading the butterknife runtime without upgrading butterknife-compiler (or vice versa); transitive dependency resolution silently pulling a mismatched butterknife version (check with gradlew dependencies); ProGuard/R8 obfuscating or removing the constructor signature while keeping the class; stale generated sources after migrating between APT and KAPT.
Related errors
- Unable to invoke {}
- Unable to assign to on
- Unable to invoke on with arguments
- Unable to create binding instance.
- @%s's %s.%s missing @%s annotation.
AI-assisted analysis of JakeWharton/butterknife@fcdebedf32 (2026-08-14).
Data as JSON: /api/errors/946cc5f74408b022.
Report an issue: GitHub.