Tencent/tinker · error · TinkerRuntimeException
Tinker instance is already set.
Error message
Tinker instance is already set.
What it means
Tinker.create(Tinker) is the low-level way to set the singleton (used internally by install/build flows) and throws TinkerRuntimeException("Tinker instance is already set.") if sInstance is already non-null. It exists so the instance can only be bound once per process; a second create indicates duplicated initialization, which Tinker rejects rather than silently replacing configuration.
Source
Thrown at tinker-android/tinker-android-lib-no-op/src/main/java/com/tencent/tinker/lib/tinker/Tinker.java:119
throw new TinkerRuntimeException("you must install tinker before get tinker sInstance");
}
synchronized (Tinker.class) {
if (sInstance == null) {
sInstance = new Builder(context).build();
}
}
return sInstance;
}
/**
* create custom tinker by {@link Tinker.Builder}
* please do it when very first your app start.
*
* @param tinker
*/
public static void create(Tinker tinker) {
if (sInstance != null) {
throw new TinkerRuntimeException("Tinker instance is already set.");
}
sInstance = tinker;
}
public static boolean isTinkerInstalled() {
return sInstalled;
}
/**
* you must install tinker first!!
*
* @param intentResult
* @param serviceClass
* @param upgradePatch
*/
public void install(Intent intentResult, Class<? extends AbstractResultService> serviceClass,
AbstractPatch upgradePatch) {
sInstalled = true;View on GitHub (pinned to 1b7ea02c23)
Solutions
- Pick exactly one initialization path per process: prefer TinkerInstaller.install(...) and delete direct create() calls.
- If you must use create(), guard it: only call when the instance is not already set (track with your own static flag or wrap in try-catch during migration).
- Move initialization to the earliest single point (Application.attachBaseContext/onCreate) so later re-entry cannot occur.
Example fix
// before TinkerInstaller.install(appLike, ...); // sets sInstance ... Tinker.create(new Tinker.Builder(app).build()); // throws: already set // after TinkerInstaller.install(appLike, ...); // single init path // remove the manual Tinker.create(...) call entirely
Defensive patterns
Strategy: validation
Validate before calling
// use the official installer only, exactly once per process
if (!Tinker.isTinkerInstalled()) {
TinkerInstaller.install(appLike, loadReporter, patchReporter, listener,
null, loadVerifyFlag, null);
}
// do not call Tinker.create(...) directly Prevention
- Prefer TinkerInstaller.install over manual Builder+create
- Initialize in one place (earliest Application callback) and remove legacy init paths
When it happens
Trigger: Calling Tinker.create(...) twice in the same process — e.g. both TinkerInstaller.install() and a manual Builder(...).build()/create() path running, or install invoked from two lifecycle callbacks, or a retained client library re-initializing.
Common situations: Migrating from manual Builder+create setup to TinkerInstaller.install and leaving the old path in place; initializing in both a base Application class and a subclass's onCreate; SDKs that embed Tinker initializing on top of the app's own initialization.
Related errors
- Tinker instance is already set.
- you must install tinker before get tinker sInstance
- upgradePatchProcessor is null.
- you must install tinker before get tinker sInstance
- intentResult must not be null.
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/f26604f88ca0ab38.
Report an issue: GitHub.