CarGuo/GSYVideoPlayer · error · IllegalStateException
Exo cache folder is locked: ${cachePath}
Error message
Exo cache folder is locked: ${cachePath} What it means
ExoPlayer's SimpleCache locks its cache folder with a lock file so only one instance can own it at a time. ExoSourceManager.getOrCreateCacheHolder checks SimpleCache.isCacheFolderLocked before creating a new cache; when the folder is already owned by another SimpleCache instance (typically in another process or a not-yet-released instance) and fallbackWhenLocked is false, it throws IllegalStateException. This protects against the classic 'Another SimpleCache instance uses the folder' crash.
Source
Thrown at gsyVideoPlayer-exo_player2/src/main/java/tv/danmaku/ijk/media/exo2/ExoSourceManager.java:467
CacheHolder cacheHolder = getOrCreateCacheHolder(context, cacheDir, true, true);
if (cacheHolder == null) {
return null;
}
mCurrentCachePath = cacheHolder.cachePath;
return cacheHolder;
}
private static synchronized CacheHolder getOrCreateCacheHolder(Context context, File cacheDir, boolean incrementRef, boolean fallbackWhenLocked) {
String cachePath = buildCachePath(context, cacheDir);
CacheHolder cacheHolder = sCacheHolderMap.get(cachePath);
if (cacheHolder == null) {
File cacheFolder = new File(cachePath);
if (SimpleCache.isCacheFolderLocked(cacheFolder)) {
if (fallbackWhenLocked) {
Log.w(TAG, "Exo cache folder is locked, fallback without cache: " + cachePath);
return null;
}
throw new IllegalStateException("Exo cache folder is locked: " + cachePath);
}
Cache cache = new SimpleCache(cacheFolder, new LeastRecentlyUsedCacheEvictor(sCacheMaxSize),
sDatabaseProvider != null ? sDatabaseProvider : new StandaloneDatabaseProvider(context));
cacheHolder = new CacheHolder(cachePath, cache);
sCacheHolderMap.put(cachePath, cacheHolder);
}
if (incrementRef) {
cacheHolder.refCount++;
}
return cacheHolder;
}
private static synchronized void releaseCacheHolder(String cachePath) {
CacheHolder cacheHolder = sCacheHolderMap.get(cachePath);
if (cacheHolder == null) {
return;
}
if (cacheHolder.refCount > 0) {View on GitHub (pinned to e5d74d3aa9)
Solutions
- Use the fallback overload acquireCacheSingleInstance(context, cacheDir, true) so playback continues without cache when the folder is locked
- Ensure ExoSourceManager.releaseAllCacheHolder(context) is called in the player release path so the lock is freed before a new instance is created
- Give each process its own cache directory (append process name to the cache dir) so two SimpleCache instances never share a folder
- If the lock is stale after a crash, delete the lock file (exoplayer_cache_lock / .lock inside the cache dir) on app start before creating the cache
Example fix
// before
Cache cache = ExoSourceManager.acquireCacheSingleInstance(context, cacheDir, false);
// after - degrade to cache-less playback instead of crashing
Cache cache = ExoSourceManager.acquireCacheSingleInstance(context, cacheDir, true);
if (cache == null) {
// proceed without cache (direct HttpDataSource)
} Defensive patterns
Strategy: fallback
Validate before calling
File cacheDir = new File(context.getCacheDir(), "exo");
if (androidx.media3.database.SimpleCache.isCacheFolderLocked(cacheDir)) {
// either release previous holders or pass fallbackWhenLocked=true
} Try / catch
try {
cache = ExoSourceManager.acquireCacheSingleInstance(ctx, cacheDir, false);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("locked")) {
cache = ExoSourceManager.acquireCacheSingleInstance(ctx, cacheDir, true); // null = play without cache
} else throw e;
} Prevention
- Always pair cache creation with ExoSourceManager.releaseAllCacheHolder in the player release path
- Give each Android process its own ExoPlayer cache directory
- Delete stale lock files at app start if the previous session crashed
When it happens
Trigger: Calling ExoSourceManager.acquireCacheSingleInstance(context, cacheDir, false) (or any path with fallbackWhenLocked=false) while the cache folder is locked: e.g. the app process died without releasing the cache, a :remote or multi-process setup has another SimpleCache on the same folder, or the previous player instance's cache was never released via ExoSourceManager.releaseAllCacheHolder.
Common situations: Multi-process apps (webview/player in separate process) sharing one cache dir; app crash leaving a stale lock file; calling Media3CacheExportUtils or CacheHelper before the previous cache holder was released; enabling ExoPlayer caching after the process was killed mid-playback.
Related errors
- ExoPlayer Cache 未初始化,请先播放视频
- Error recreate zero-size file %s
- Max count must be positive number!
- Max size must be positive number!
- Subtitle url is empty
AI-assisted analysis of CarGuo/GSYVideoPlayer@e5d74d3aa9 (2026-08-14).
Data as JSON: /api/errors/ca96c95f73ce52a4.
Report an issue: GitHub.