Tencent/tinker · error · TinkerRuntimeException
resultServiceClass is null.
Error message
resultServiceClass is null.
What it means
AbstractResultService.runResultService is the static helper TinkerPatchService uses to dispatch the final PatchResult to the app's result service. It throws when the resultServiceClass string argument is null, i.e., the flow tried to report a patch result without knowing which service class to target. This is an integration/configuration error, not a patch-content error.
Source
Thrown at tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/service/AbstractResultService.java:41
import com.tencent.tinker.loader.shareutil.ShareTinkerLog;
import com.tencent.tinker.loader.TinkerRuntimeException;
import com.tencent.tinker.loader.shareutil.ShareIntentUtil;
/**
* Created by zhangshaowen on 16/3/14.
*/
public abstract class AbstractResultService extends IntentService {
private static final String TAG = "Tinker.AbstractResultService";
private static final String RESULT_EXTRA = "result_extra";
public AbstractResultService() {
super("TinkerResultService");
}
public static void runResultService(Context context, PatchResult result, String resultServiceClass) {
if (resultServiceClass == null) {
throw new TinkerRuntimeException("resultServiceClass is null.");
}
try {
Intent intent = new Intent();
intent.setClassName(context, resultServiceClass);
intent.putExtra(RESULT_EXTRA, result);
context.startService(intent);
} catch (Throwable throwable) {
ShareTinkerLog.e(TAG, "run result service fail, exception:" + throwable);
}
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent == null) {
ShareTinkerLog.e(TAG, "AbstractResultService received a null intent, ignoring.");
return;
}
PatchResult result = (PatchResult) ShareIntentUtil.getSerializableExtra(intent, RESULT_EXTRA);View on GitHub (pinned to 1b7ea02c23)
Solutions
- Always apply patches through TinkerInstaller.onReceiveUpgradePatch(context, patchPath), which starts TinkerPatchService with all required extras.
- If you must start the service yourself, replicate runPatchService: include patch path extra and the result service class name extra.
- Override onStartCommand/onHandleIntent defensively in a subclass to drop intents that lack extras instead of crashing the :patch process.
- Keep your AbstractResultService subclass registered in the manifest and excluded from obfuscation.
Example fix
// before (custom flow) Intent i = new Intent(context, TinkerPatchService.class); context.startService(i); // after TinkerInstaller.onReceiveUpgradePatch(context, patchFile.getAbsolutePath());
Defensive patterns
Strategy: validation
Validate before calling
String resultClass = intent != null
? TinkerPatchService.getPatchResultExtra(intent) : null;
if (resultClass == null) {
// do not run the result service; the apply flow is misconfigured
logOrReport("patch intent missing result class extra");
return;
}
AbstractResultService.runResultService(context, result, resultClass); Try / catch
try {
AbstractResultService.runResultService(context, result, resultClass);
} catch (TinkerRuntimeException e) {
// swallow and report: never crash the :patch process over result reporting
reportResultDispatchFailure(e);
} Prevention
- Never start TinkerPatchService directly; always go through TinkerInstaller.onReceiveUpgradePatch.
- If wrapping the service, replicate runPatchService's extras (patch path + result class) exactly.
- Register your AbstractResultService subclass in the manifest and keep it un-obfuscated with proguard keep rules.
When it happens
Trigger: TinkerPatchService.onHandleIntent finishes doApplyPatch and calls runResultService with the RESULT_CLASS_EXTRA string that was null — this happens when the patch service intent was started without extras, e.g., a custom component starts TinkerPatchService directly instead of going through TinkerInstaller.onReceiveUpgradePatch / TinkerPatchService.runPatchService.
Common situations: App code or another library broadcasts/starts the :patch process service manually (redelivery on startService with a null intent also reaches onHandleIntent with null extras); a custom upgrade-patch entry point forgets to put the result class extra; proguard renaming breaking the component while the extra still resolves.
Related errors
- getPatchPathExtra, but intent is null
- getPatchUseEmergencyMode, but intent is null
- getPatchResultExtra, but intent is null
- libName or context is null!
- libName or appLike is null!
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/d1c5958625e7d8f6.
Report an issue: GitHub.