CarGuo/GSYVideoPlayer · error · ProxyCacheException

Error reading source ${errorsCount} times

Error message

Error reading source ${errorsCount} times

What it means

FileCache's constructor makes the parent directory, decides between the completed file (read-only 'r') or the .download temp file ('rw'), and opens a RandomAccessFile on it. Any IOException in that setup - unwritable dir, missing permissions, file locked by another process - becomes ProxyCacheException('Error using file <path> as disc cache').

Source

Thrown at gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/ProxyCache.java:56

        while (!cache.isCompleted() && cache.available() < (offset + length) && !stopped) {
            readSourceAsync();
            waitForSourceData();
            checkReadSourceErrorsCount();
        }
        int read = cache.read(buffer, offset, length);
        if (cache.isCompleted() && percentsAvailable != 100) {
            percentsAvailable = 100;
            onCachePercentsAvailableChanged(100);
        }
        return read;
    }

    private void checkReadSourceErrorsCount() throws ProxyCacheException {
        int errorsCount = readSourceErrorsCount.get();
        if (errorsCount >= MAX_READ_SOURCE_ATTEMPTS) {
            readSourceErrorsCount.set(0);
            throw new ProxyCacheException("Error reading source " + errorsCount + " times");
        }
    }

    public void shutdown() {
        synchronized (stopLock) {
            try {
                stopped = true;
                if (sourceReaderThread != null) {
                    sourceReaderThread.interrupt();
                }
                cache.close();
            } catch (ProxyCacheException e) {
                onError(e);
            }
        }
    }

    private synchronized void readSourceAsync() throws ProxyCacheException {

View on GitHub (pinned to e5d74d3aa9)

Solutions

  1. Use context.getExternalCacheDir() or context.getCacheDir() as the proxy cache root (app-scoped)
  2. Check usable space before playback on low-storage devices and clear LRU files via the configured DiskUsage
  3. Ensure only one HttpProxyCacheServer instance per cache directory
  4. Verify Environment.getExternalStorageState() when the cache dir is user-configurable

Example fix

// before
new HttpProxyCacheServer.Builder(context)
    .cacheDirectory(new File("/sdcard/gsy_proxy_cache"))
    .build();

// after - app-scoped cache dir
new HttpProxyCacheServer.Builder(context)
    .cacheDirectory(new File(context.getExternalCacheDir(), "gsy_proxy_cache"))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

File cacheDir = new File(context.getExternalCacheDir(), "proxy");
String state = Environment.getExternalStorageState();
boolean writable = Environment.MEDIA_MOUNTED.equals(state)
        && cacheDir.canWrite();
if (!writable) cacheDir = new File(context.getCacheDir(), "proxy");

Try / catch

try { server = new Builder(ctx).cacheDirectory(dir).build(); }
catch (ProxyCacheException e) {
    if (String.valueOf(e.getMessage()).contains("as disc cache")) {
        server = new Builder(ctx).cacheDirectory(new File(ctx.getCacheDir(), "proxy")).build();
    } else throw e;
}

Prevention

When it happens

Trigger: HttpProxyCacheServer starts caching a new url and creates FileCache for the .download temp file when: cache directory is on read-only/unmounted storage, disk is full, another process holds the file, or a non-existent parent path (Files.makeDir failed differently).

Common situations: Cache dir configured to external storage that got unmounted; Android scoped-storage restrictions applied to a shared cache path; disk-full devices; two proxy servers pointed at the same cache folder from different processes.

Related errors


AI-assisted analysis of CarGuo/GSYVideoPlayer@e5d74d3aa9 (2026-08-14). Data as JSON: /api/errors/466f26eaf1466149. Report an issue: GitHub.