didi/DoKit · error · IllegalStateException
Cannot set the LeakDirectoryProvider after it has already be
Error message
Cannot set the LeakDirectoryProvider after it has already been set. Try setting it before installing the RefWatcher.
What it means
LeakCanaryInternals.setLeakDirectoryProvider() sets the process-wide directory provider used to store heap dumps. Because the analyzer, activities, and services all read this static field, it can only be set once; setting it after the RefWatcher is installed risks half the components using the old location, so a second set throws IllegalStateException.
Source
Thrown at Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/internal/LeakCanaryInternals.java:198
notificationManager.createNotificationChannel(notificationChannel);
}
builder.setChannelId(NOTIFICATION_CHANNEL_ID);
}
if (SDK_INT < JELLY_BEAN) {
return builder.getNotification();
} else {
return builder.build();
}
}
public static Executor newSingleThreadExecutor(String threadName) {
return Executors.newSingleThreadExecutor(new LeakCanarySingleThreadFactory(threadName));
}
public static void setLeakDirectoryProvider(LeakDirectoryProvider leakDirectoryProvider) {
if (LeakCanaryInternals.leakDirectoryProvider != null) {
throw new IllegalStateException("Cannot set the LeakDirectoryProvider after it has already "
+ "been set. Try setting it before installing the RefWatcher.");
}
LeakCanaryInternals.leakDirectoryProvider = leakDirectoryProvider;
}
public static LeakDirectoryProvider getLeakDirectoryProvider(Context context) {
LeakDirectoryProvider leakDirectoryProvider = LeakCanaryInternals.leakDirectoryProvider;
if (leakDirectoryProvider == null) {
leakDirectoryProvider = new DefaultLeakDirectoryProvider(context);
}
return leakDirectoryProvider;
}
private LeakCanaryInternals() {
throw new AssertionError();
}
}
View on GitHub (pinned to 626827cddb)
Solutions
- Call setLeakDirectoryProvider before buildAndInstall(), in the same single init block
- Check the current state first: only set when LeakCanaryInternals-installed watcher is null / provider not yet set
- If reconfiguration is genuinely needed, do it in a fresh process rather than at runtime
Example fix
// before LeakCanary.refWatcher(this).buildAndInstall(); LeakCanaryInternals.setLeakDirectoryProvider(customProvider); // throws // after LeakCanaryInternals.setLeakDirectoryProvider(customProvider); LeakCanary.refWatcher(this).buildAndInstall();
Defensive patterns
Strategy: validation
Validate before calling
// in the single init block, before install: LeakCanaryInternals.setLeakDirectoryProvider(customProvider); LeakCanary.refWatcher(context).buildAndInstall();
Prevention
- Configure the directory provider and install the watcher in one startup block, in that order
- Do not expose runtime reconfiguration of the heap dump directory in debug menus
When it happens
Trigger: Calling LeakCanaryInternals.setLeakDirectoryProvider(provider) after a previous call, in particular after LeakCanary's buildAndInstall() already ran (installation itself configures the provider). Typical in debug tool setups (e.g. DoraemonKit panel) that let the user change the heap dump location at runtime.
Common situations: App initializes LeakCanary in Application.onCreate, then a debug menu tries to redirect heap dumps to a custom folder. Two libraries both attempting to configure the provider. Tests that reconfigure per test method without process reset.
Related errors
- buildAndInstall() should only be called once.
- maxStoredHeapDumps must be at least 1
- leakTraceAsFakeException() can only be called when leakFound
- Could not find char array in {}
- File does not exist: {}
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/49b46c9c0513bfff.
Report an issue: GitHub.