didi/DoKit · error · IllegalArgumentException

maxStoredHeapDumps must be at least 1

Error message

maxStoredHeapDumps must be at least 1

What it means

DefaultLeakDirectoryProvider stores heap dumps in app storage and prunes old ones to stay under maxStoredHeapDumps. Its constructor validates that the cap is at least 1; zero or negative would mean heap dumps can never be persisted, so the constructor fails fast with IllegalArgumentException.

Source

Thrown at Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/DefaultLeakDirectoryProvider.java:67

  private static final String HPROF_SUFFIX = ".hprof";
  private static final String PENDING_HEAPDUMP_SUFFIX = "_pending" + HPROF_SUFFIX;

  /** 10 minutes */
  private static final int ANALYSIS_MAX_DURATION_MS = 10 * 60 * 1000;

  private final Context context;
  private final int maxStoredHeapDumps;

  private volatile boolean writeExternalStorageGranted;
  private volatile boolean permissionNotificationDisplayed;

  public DefaultLeakDirectoryProvider(@NonNull Context context) {
    this(context, DEFAULT_MAX_STORED_HEAP_DUMPS);
  }

  public DefaultLeakDirectoryProvider(@NonNull Context context, int maxStoredHeapDumps) {
    if (maxStoredHeapDumps < 1) {
      throw new IllegalArgumentException("maxStoredHeapDumps must be at least 1");
    }
    this.context = context.getApplicationContext();
    this.maxStoredHeapDumps = maxStoredHeapDumps;
  }

  @Override
  public @NonNull
  List<File> listFiles(@NonNull FilenameFilter filter) {
    if (!hasStoragePermission()) {
      requestWritePermissionNotification();
    }
    List<File> files = new ArrayList<>();

    File[] externalFiles = externalStorageDirectory().listFiles(filter);
    if (externalFiles != null) {
      files.addAll(Arrays.asList(externalFiles));
    }

View on GitHub (pinned to 626827cddb)

Solutions

  1. Pass a value >= 1; LeakCanary's own default is DEFAULT_MAX_STORED_HEAP_DUMPS (7)
  2. If the intent was 'disable leak analysis', do not construct the provider — build a disabled RefWatcher (RefWatcher.DISABLED) instead
  3. Clamp user-supplied settings: Math.max(1, configuredValue) at the configuration boundary

Example fix

// before
new DefaultLeakDirectoryProvider(context, 0);

// after
new DefaultLeakDirectoryProvider(context, Math.max(1, config.maxHeapDumps));
Defensive patterns

Strategy: validation

Validate before calling

int capped = Math.max(1, configuredMaxHeapDumps);
new DefaultLeakDirectoryProvider(context, capped);

Prevention

When it happens

Trigger: Constructing new DefaultLeakDirectoryProvider(context, maxStoredHeapDumps) with 0 or a negative value — typically from a hardcoded config, a BuildConfig field, or a computed value (e.g. user preference mapped to 'keep no dumps') that was never validated.

Common situations: Teams wiring LeakCanary config from a remote-config or debug-settings screen where 0 is used to mean 'disable heap dumps'. Copy-pasted builder code with a placeholder 0. Using the DoraemonKit wrapper that exposes this provider with a configurable dump count.

Related errors


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/54bb7619ab2678bd. Report an issue: GitHub.