nostra13/Android-Universal-Image-Loader · error · IllegalArgumentException

cacheMaxSize argument must be positive number

Error message

cacheMaxSize argument must be positive number

What it means

LruDiskCache's constructor throws IllegalArgumentException when cacheMaxSize is negative. The documented contract is: 0 means unlimited (normalized internally to Long.MAX_VALUE), positive means a byte cap; negative is meaningless and rejected. Note the message text ('must be positive number') is slightly misleading — 0 is actually accepted.

Source

Thrown at library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/LruDiskCache.java:88

	}

	/**
	 * @param cacheDir          Directory for file caching
	 * @param reserveCacheDir   null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.
	 * @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator
	 *                          Name generator} for cached files. Generated names must match the regex
	 *                          <strong>[a-z0-9_-]{1,64}</strong>
	 * @param cacheMaxSize      Max cache size in bytes. <b>0</b> means cache size is unlimited.
	 * @param cacheMaxFileCount Max file count in cache. <b>0</b> means file count is unlimited.
	 * @throws IOException if cache can't be initialized (e.g. "No space left on device")
	 */
	public LruDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator, long cacheMaxSize,
			int cacheMaxFileCount) throws IOException {
		if (cacheDir == null) {
			throw new IllegalArgumentException("cacheDir" + ERROR_ARG_NULL);
		}
		if (cacheMaxSize < 0) {
			throw new IllegalArgumentException("cacheMaxSize" + ERROR_ARG_NEGATIVE);
		}
		if (cacheMaxFileCount < 0) {
			throw new IllegalArgumentException("cacheMaxFileCount" + ERROR_ARG_NEGATIVE);
		}
		if (fileNameGenerator == null) {
			throw new IllegalArgumentException("fileNameGenerator" + ERROR_ARG_NULL);
		}

		if (cacheMaxSize == 0) {
			cacheMaxSize = Long.MAX_VALUE;
		}
		if (cacheMaxFileCount == 0) {
			cacheMaxFileCount = Integer.MAX_VALUE;
		}

		this.reserveCacheDir = reserveCacheDir;
		this.fileNameGenerator = fileNameGenerator;
		initCache(cacheDir, reserveCacheDir, cacheMaxSize, cacheMaxFileCount);

View on GitHub (pinned to ba33ec64d0)

Solutions

  1. Pass a positive byte size (e.g. 50 * 1024 * 1024) or 0 for unlimited.
  2. Clamp computed sizes: Math.max(0, available - reserve).
  3. If -1 is your 'unset' sentinel, map it to 0 before constructing the cache.

Example fix

// before
long size = freeDiskBytes - RESERVE; // negative on nearly-full disk
new LruDiskCache(dir, null, gen, size, 0);

// after
long size = Math.max(0, freeDiskBytes - RESERVE);
new LruDiskCache(dir, null, gen, size, 0);
Defensive patterns

Strategy: validation

Validate before calling

long sizeArg = (cacheMaxSize >= 0) ? cacheMaxSize : 0; // 0 == unlimited
new LruDiskCache(dir, reserve, gen, sizeArg, fileCount);

Prevention

When it happens

Trigger: Calling new LruDiskCache(..., cacheMaxSize, ...) with a negative long, e.g. from diskCacheExtraConfiguration(...) with a negative maxCacheSize, or from arithmetic like (availableBytes - reserve) going negative.

Common situations: Computing cache size from free disk space that underflows when the reserve exceeds available; configuration constants defaulting to -1 as 'unset' and passed through unnormalized; typos in size config.

Related errors


AI-assisted analysis of nostra13/Android-Universal-Image-Loader@ba33ec64d0 (2026-08-14). Data as JSON: /api/errors/bb04deb102ad2569. Report an issue: GitHub.