Tencent/tinker · critical · TinkerRuntimeException
get public key md5 is null
Error message
get public key md5 is null
What it means
During ShareSecurityCheck.init, the app's signing certificate bytes are hashed with MD5; if SharePatchFileUtil.getMD5(...) returns null (digest could not be computed), TinkerRuntimeException("get public key md5 is null") is thrown. The loader needs this md5 to compare with the patch's signing identity, so failing here blocks all security checks.
Source
Thrown at tinker-android/tinker-android-loader/src/main/java/com/tencent/tinker/loader/shareutil/ShareSecurityCheck.java:170
}
} catch (Exception e) {
ShareTinkerLog.e(TAG, path.getAbsolutePath(), e);
}
}
}
return false;
}
@SuppressLint("PackageManagerGetSignatures")
private void init(Context context) {
ByteArrayInputStream stream = null;
try {
PackageManager pm = context.getPackageManager();
String packageName = context.getPackageName();
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
mPublicKeyMd5 = SharePatchFileUtil.getMD5(packageInfo.signatures[0].toByteArray());
if (mPublicKeyMd5 == null) {
throw new TinkerRuntimeException("get public key md5 is null");
}
} catch (Exception e) {
throw new TinkerRuntimeException("ShareSecurityCheck init public key fail", e);
} finally {
SharePatchFileUtil.closeQuietly(stream);
}
}
}
View on GitHub (pinned to 1b7ea02c23)
Solutions
- Verify the app is properly signed and installed (pm dump or apksigner verify on the APK).
- Confirm context is the real application context, not a mocked/instrumented one, when the check runs.
- If you ship a fork, guard for null signatures before hashing and fail closed with a clearer error.
- Reinstall the APK normally and retry patch loading.
Example fix
// before
mPublicKeyMd5 = SharePatchFileUtil.getMD5(packageInfo.signatures[0].toByteArray());
// after
byte[] sigBytes = packageInfo.signatures != null && packageInfo.signatures.length > 0
? packageInfo.signatures[0].toByteArray() : null;
mPublicKeyMd5 = sigBytes != null ? SharePatchFileUtil.getMD5(sigBytes) : null; Defensive patterns
Strategy: try-catch
Validate before calling
PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
if (pi.signatures == null || pi.signatures.length == 0 || pi.signatures[0] == null) {
// signature metadata unavailable: do not attempt security check
} Try / catch
try {
ShareSecurityCheck check = new ShareSecurityCheck(context);
} catch (TinkerRuntimeException e) {
// 'get public key md5 is null' or init failure: block patch loading on this install
} Prevention
- Ship only properly signed release builds when testing patch flows.
- Do not run patch loads from instrumented/mocked contexts.
- Treat any security-check init failure as 'patching disabled', never retry in a loop.
When it happens
Trigger: Constructing ShareSecurityCheck(context) when getMD5(packageInfo.signatures[0].toByteArray()) returns null — an empty/null signature byte array fed to the digest, typically on ROMs reporting null signatures.
Common situations: Running on emulators or modified ROMs where PackageManager returns empty signature arrays; apps installed in unusual ways (debug bridges, some enterprise stores) with missing signer info; in practice rare — most failures surface as the wrapped exception in error 218.
Related errors
- ShareSecurityCheck file %s, size %d verifyPatchMetaSignature
- ShareSecurityCheck init public key fail
- patch dex file md5 is mismatch, but path is null!!!!
- resource file md5 mismatch, but patch resource file not foun
- Filename contains NUL byte: ${Arrays.toString(nameBytes)}
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/94197a6790077164.
Report an issue: GitHub.