Tencent/tinker · error · ClassNotFoundException
cannot find class: {}
Error message
cannot find class: {} What it means
Thrown by Tinker's ServiceBinderInterceptor when a dynamic Proxy invocation handler cannot load a class named in an IPC method invocation from any of the merged classloaders (patch PathClassLoader plus BootClassLoader). The interceptor proxies framework binder interfaces (e.g. IServiceManager, IActivityManager) so that parceled arguments coming from the patched app can be resolved. If a class referenced by the call is only present in a classloader not reachable from the merged set, ClassNotFoundException is thrown after all candidate loaders fail.
Source
Thrown at tinker-android/tinker-android-loader/src/main/java/com/tencent/tinker/loader/hotplug/interceptor/ServiceBinderInterceptor.java:176
cl = uniqueCls.iterator().next();
} else {
cl = new ClassLoader() {
@Override
protected Class<?> loadClass(String className, boolean resolve)
throws ClassNotFoundException {
Class<?> res = null;
for (ClassLoader cl : uniqueCls) {
try {
// fix some device PathClassLoader behind BootClassLoader which lead to ClassNotFoundException
res = cl.loadClass(className);
} catch (Throwable ignore) {
}
if (res != null) {
return res;
}
}
throw new ClassNotFoundException("cannot find class: " + className);
}
};
}
try {
return (T) Proxy.newProxyInstance(cl, mergedItfs, handler);
} catch (Throwable thr2) {
throw new RuntimeException("cl: " + cl, thr);
}
}
}
private static Class<?>[] getAllInterfacesThroughDeriveChain(Class<?> clazz) {
if (clazz == null) {
return null;
}
final Set<Class<?>> itfs = new HashSet<>(10);
while (!Object.class.equals(clazz)) {
itfs.addAll(Arrays.asList(clazz.getInterfaces()));View on GitHub (pinned to 1b7ea02c23)
Solutions
- Verify the class named in the exception actually exists in the installed base APK or patch dex (use dexdump / apktool on both APKs).
- If the class lives in a separate dynamic feature or plugin classloader, add that classloader to the interceptor's merged set (uniqueCls) before the proxy is created.
- Ensure patch and base APK apply identical proguard mappings so class names resolve consistently.
- On affected OEM devices, avoid the component-hotplug proxy path or update Tinker, since the multi-classloader loop already works around BootClassLoader ordering issues.
- Catch ClassNotFoundException at the proxy boundary and degrade gracefully (skip hotplug for that call) instead of crashing the process.
Example fix
// before
res = cl.loadClass(className); // last loop iteration, res stays null
// after
try {
res = cl.loadClass(className);
} catch (Throwable ignore) {
// try next classloader
}
if (res == null && isOptionalIpcClass(className)) {
return Object.class; // or skip argument handling
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before enabling component hotplug proxying, ensure the classes it will reference exist
Class<?> probe = null;
for (ClassLoader cl : new ClassLoader[]{ app.getClassLoader(), ClassLoader.getSystemClassLoader() }) {
try { probe = cl.loadClass("com.example.patched.ParcelableArg"); break; } catch (Throwable ignore) {}
}
if (probe == null) { /* do not enable proxy for this call */ } Try / catch
try {
Object proxy = ServiceBinderInterceptor.proxyServiceManagement(...);
} catch (ClassNotFoundException cnfe) {
// class missing from all merged classloaders: skip hotplug proxy, keep default binder
} catch (RuntimeException re) {
Throwable cause = re.getCause(); // original failure chained by the interceptor
} Prevention
- Keep proguard mappings identical between base APK and patch.
- Do not pass Parcelable types that only exist in a side-loaded dex through proxied binder calls.
- Test component hotplug on the OEM ROMs you ship to, especially those with unusual classloader hierarchies.
When it happens
Trigger: Any proxied binder call whose Parcel contains a class name that resolves in none of the collected classloaders: cl.loadClass(className) returns null / throws for every entry of uniqueCls, then 'throw new ClassNotFoundException("cannot find class: " + className)' fires inside the InvocationHandler.
Common situations: Using Tinker's component hotplug (proxy running Services) on OEM ROMs where the PathClassLoader sits behind the BootClassLoader; a patch that references a class removed or renamed between patch and base APK; cross-process IPC passing custom Parcelable types loaded by a plugin/second dex set; obfuscated or missing classes after aggressive proguard on the patch.
Related errors
- fakeBinder does not return fakeInterface, binder: {}, itf: {
- createInlineFence failed
- failed to fetch instance of ActivityThread.
- unexpected xml parser state when parsing incremental compone
- Not initialized!!
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/2c7b76d36d87f579.
Report an issue: GitHub.