Tencent/tinker · error · TinkerRuntimeException
loadReporter is already set.
Error message
loadReporter is already set.
What it means
Tinker.Builder.loadReport(LoadReporter) throws TinkerRuntimeException("loadReporter is already set.") on the second invocation — the reporter is a set-once builder property. This mirrors the other guards: load reporting must have exactly one owner, and re-assigning it (e.g. base config plus app config) would silently drop one set of callbacks.
Source
Thrown at tinker-android/tinker-android-lib-no-op/src/main/java/com/tencent/tinker/lib/tinker/Tinker.java:338
}
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
- Register exactly one LoadReporter — the app's custom one if it exists, otherwise DefaultLoadReporter — in a single loadReport() call.
- If a base implementation plus extra behavior is needed, wrap both in one composite LoadReporter and register the composite.
- Keep the entire builder chain in one method to make duplicate calls visually obvious.
Example fix
// before builder.loadReport(new DefaultLoadReporter(app)); // base init builder.loadReport(new MyAppLoadReporter(app)); // throws: already set // after LoadReporter reporter = useCustom ? new MyAppLoadReporter(app) : new DefaultLoadReporter(app); builder.loadReport(reporter);
Defensive patterns
Strategy: validation
Validate before calling
LoadReporter reporter = useCustom ? new MyAppLoadReporter(app) : new DefaultLoadReporter(app); builder.loadReport(reporter); // exactly one call
Prevention
- One reporter per builder; wrap multiple behaviors in a composite reporter
- Centralize the builder chain in a single init method
When it happens
Trigger: Calling loadReport(...) twice on the same Builder instance — shared init helper applying a default reporter plus the app applying its custom one, or a duplicated chain line left behind after refactoring initialization code.
Common situations: A common module configures DefaultLoadReporter and the host app wants a custom LoadReporter; merging Tinker init from two teams/SDKs; builder stored in a static field and configured in stages.
Related errors
- tinkerFlag is already set.
- tinkerLoadVerifyFlag must not be null.
- tinkerLoadVerifyFlag is already set.
- loadReporter must not be null.
- patchReporter must not be null.
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/b567c6941ddcef4d.
Report an issue: GitHub.