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

  1. Verify the app is properly signed and installed (pm dump or apksigner verify on the APK).
  2. Confirm context is the real application context, not a mocked/instrumented one, when the check runs.
  3. If you ship a fork, guard for null signatures before hashing and fail closed with a clearer error.
  4. 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

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


AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14). Data as JSON: /api/errors/94197a6790077164. Report an issue: GitHub.