Tencent/tinker · error · TinkerRuntimeException

tinkerLoadVerifyFlag is already set.

Error message

tinkerLoadVerifyFlag is already set.

What it means

Builder.tinkerLoadVerifyFlag may only be called once, same policy as the other builder setters: the stored Boolean is used both as the value and as the 'already set' marker, so a second call throws instead of silently overwriting the first configuration.

Source

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

            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

  1. Set the flag once, at a single configuration site owned by the app module.
  2. If layered configuration is needed, compute the final boolean first and call the setter once.
  3. Instantiate a new Builder for each independent configuration (e.g., per test).

Example fix

// before
builder.tinkerLoadVerifyFlag(true);   // base init
builder.tinkerLoadVerifyFlag(false);  // app override -> throws

// after
boolean verify = flavor == Release ? true : false;
builder.tinkerLoadVerifyFlag(verify); // single call
Defensive patterns

Strategy: validation

Validate before calling

boolean verify = flavor == ReleaseFlavor || serverConfig.forceVerify;
builder.tinkerLoadVerifyFlag(verify); // exactly one call, computed beforehand

Prevention

When it happens

Trigger: Calling tinkerLoadVerifyFlag(...) twice on the same Builder — e.g., a shared init helper sets it, then the app's own setup sets it again with a different value.

Common situations: Library and app both configuring tinker; copy-pasted config blocks; a builder field reused across multiple init attempts in tests.

Related errors


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