Tencent/tinker · error · TinkerRuntimeException
loadReporter is already set.
Error message
loadReporter is already set.
What it means
Thrown by Tinker.Builder.loadReport when the LoadReporter has already been assigned. The builder enforces single assignment of each collaborator so Tinker's lifecycle callbacks always go to exactly one reporter. Calling loadReport twice on the same Builder instance violates that contract.
Source
Thrown at tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/tinker/Tinker.java:389
}
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) {
throw new TinkerRuntimeException("patchReporter must not be null.");
}
if (this.patchReporter != null) {
throw new TinkerRuntimeException("patchReporter is already set.");
}
this.patchReporter = patchReporter;
return this;
}
public Builder listener(PatchListener listener) {
if (listener == null) {View on GitHub (pinned to 1b7ea02c23)
Solutions
- Ensure loadReport is called exactly once per Builder instance; move all builder configuration into a single Tinker.install flow.
- If multiple components need load feedback, keep one LoadReporter and fan out events from it instead of registering several.
- Check that Tinker.isTinkerInstalled() is false before building/installing again to avoid double initialization on process restarts.
Example fix
// before builder.loadReport(new DefaultLoadReporter(context)); builder.loadReport(new MyLoadReporter(context)); // throws // after builder.loadReport(new MyLoadReporter(context)); // single reporter that delegates where needed
Defensive patterns
Strategy: validation
Validate before calling
// before configuring: ensure not already installed, and configure once
if (!Tinker.isTinkerInstalled()) {
Tinker.install(new Tinker.Builder(app)
.loadReport(new DefaultLoadReporter(app))
.patchReport(new DefaultPatchReporter(app))
.listener(new DefaultPatchListener(app))
.build());
} Prevention
- Centralize all Tinker builder configuration in one method invoked from ApplicationLike#onCreate.
- Never cache the Tinker.Builder in a static field that can be reconfigured later.
- Add an isTinkerInstalled() check before building so process re-entry cannot double-configure.
When it happens
Trigger: Calling Tinker.with(app).getBuilder()... i.e. invoking builder.loadReport(...) a second time on the same Builder instance — typically in a custom ApplicationLike#onCreate where Tinker is installed in multiple process branches or the builder is stored in a static field and configured again.
Common situations: Re-running initialization code after a configuration change, sharing one Builder across helper classes that each try to set a reporter, or copy-pasting the sample DefaultLoadReporter wiring twice. Also occurs when Tinker.install is called from both the Application and a library's init block.
Related errors
- tinkerFlag is already set.
- tinkerLoadVerifyFlag is already set.
- patchReporter is already set.
- listener is already set.
- Tinker instance is already set.
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/437fb69fc89927a6.
Report an issue: GitHub.