Tencent/tinker · error · TinkerRuntimeException
tinkerLoadVerifyFlag is already set.
Error message
tinkerLoadVerifyFlag is already set.
What it means
Tinker.Builder.tinkerLoadVerifyFlag(Boolean) is a set-once fluent setter: after the null check it throws TinkerRuntimeException("tinkerLoadVerifyFlag is already set.") when the field has already been assigned. Like the other builder guards, this prevents two different code paths from each configuring the verify flag, which would silently change whether patches are md5-checked at load time.
Source
Thrown at tinker-android/tinker-android-lib-no-op/src/main/java/com/tencent/tinker/lib/tinker/Tinker.java:327
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;
}
public Builder patchReporter(PatchReporter patchReporter) {
if (patchReporter == null) {View on GitHub (pinned to 1b7ea02c23)
Solutions
- Resolve the final flag once (prefer the stricter true when in doubt) and call the setter a single time.
- Compute the decision before building: boolean verify = isQa || cfgFlag; builder.tinkerLoadVerifyFlag(verify).
- Create a fresh Builder per initialization and never share/reuse it across code paths.
Example fix
// before builder.tinkerLoadVerifyFlag(true); // QA default if (!isQa) builder.tinkerLoadVerifyFlag(false); // throws: already set // after builder.tinkerLoadVerifyFlag(isQa); // single decision, one call
Defensive patterns
Strategy: validation
Validate before calling
boolean verify = isQaBuild || Boolean.TRUE.equals(cfgFlag); builder.tinkerLoadVerifyFlag(verify); // single call
Prevention
- One decision point for the verify flag; prefer the stricter (true) value on conflict
- Never share a Builder instance across configuration layers
When it happens
Trigger: Calling tinkerLoadVerifyFlag(...) twice on the same Builder — e.g. a shared init helper sets true for QA builds and the app's own chain then sets false, or a duplicated chain line after merge/refactor.
Common situations: Debug/QA overlays that 'adjust' a base configuration; builder kept as a long-lived field receiving repeated configuration; two SDKs both embedding Tinker init logic.
Related errors
- tinkerFlag is already set.
- tinkerLoadVerifyFlag must not be null.
- loadReporter is already set.
- tinkerFlag is already set.
- tinkerLoadVerifyFlag must not be null.
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/d9e3cffa6b2e153e.
Report an issue: GitHub.