Tencent/tinker · error · TinkerRuntimeException

tinkerLoadVerifyFlag must not be null.

Error message

tinkerLoadVerifyFlag must not be null.

What it means

Builder.tinkerLoadVerifyFlag(Boolean) rejects a null argument. The flag controls whether dex/so MD5s are verified on every load (slower but safer), and the builder stores it as a Boolean tri-state (null = unset); passing null would be indistinguishable from 'not configured', so it fails fast.

Source

Thrown at tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/tinker/Tinker.java:375

                ShareTinkerLog.e(TAG, "patchDirectory is null!");
                return;
            }
            this.patchInfoFile = SharePatchFileUtil.getPatchInfoFile(patchDirectory.getAbsolutePath());
            this.patchInfoLockFile = SharePatchFileUtil.getPatchInfoLockFile(patchDirectory.getAbsolutePath());
            ShareTinkerLog.w(TAG, "tinker patch directory: %s", patchDirectory);
        }

        public Builder tinkerFlags(int tinkerFlags) {
            if (this.status != -1) {
                throw new TinkerRuntimeException("tinkerFlag is already set.");
            }
            this.status = tinkerFlags;
            return this;
        }

        public Builder tinkerLoadVerifyFlag(Boolean verifyMd5WhenLoad) {
            if (verifyMd5WhenLoad == null) {
                throw new TinkerRuntimeException("tinkerLoadVerifyFlag must not be null.");
            }
            if (this.tinkerLoadVerifyFlag != null) {
                throw new TinkerRuntimeException("tinkerLoadVerifyFlag is already set.");
            }
            this.tinkerLoadVerifyFlag = verifyMd5WhenLoad;
            return this;
        }

        public Builder loadReport(LoadReporter loadReporter) {
            if (loadReporter == null) {
                throw new TinkerRuntimeException("loadReporter must not be null.");
            }
            if (this.loadReporter != null) {
                throw new TinkerRuntimeException("loadReporter is already set.");
            }
            this.loadReporter = loadReporter;
            return this;
        }

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Default the value before calling the builder: loadVerifyFlag = config.getOrFalse('verifyOnLoad').
  2. In Kotlin, use `config.verifyOnLoad ?: false`.
  3. Fail config parsing loudly when a required boolean is missing instead of propagating null.

Example fix

// before
Boolean v = remoteConfig.getBoolean("tinkerLoadVerify"); // null when absent
builder.tinkerLoadVerifyFlag(v);

// after
boolean v = Boolean.TRUE.equals(remoteConfig.getBoolean("tinkerLoadVerify"));
builder.tinkerLoadVerifyFlag(v);
Defensive patterns

Strategy: validation

Validate before calling

Boolean remote = remoteConfig.getBoolean("tinkerLoadVerify");
builder.tinkerLoadVerifyFlag(Boolean.TRUE.equals(remote)); // never null

Type guard

public static boolean nonNullFlag(Boolean b) {
    return b != null && b;
}

Prevention

When it happens

Trigger: Calling tinkerLoadVerifyFlag(null) — usually because a config value was read from a remote-config map or a nullable field that was never defaulted.

Common situations: Remote-config-driven init where the key is missing and the map returns null; Kotlin nullable Boolean passed without defaulting; migration from a config schema where the flag was optional.

Related errors


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