{"record":{"id":"8f464a99897d0883","repo":"CarGuo/GSYVideoPlayer","slug":"error-using-file-file-as-disc-cache","errorCode":null,"errorMessage":"Error using file ${file} as disc cache","messagePattern":"Error using file (.+?) as disc cache","errorType":"exception","errorClass":"ProxyCacheException","httpStatus":null,"severity":"error","filePath":"gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/file/FileCache.java","lineNumber":39,"sourceCode":"    private RandomAccessFile dataFile;\n\n    public FileCache(File file) throws ProxyCacheException {\n        this(file, new UnlimitedDiskUsage());\n    }\n\n    public FileCache(File file, DiskUsage diskUsage) throws ProxyCacheException {\n        try {\n            if (diskUsage == null) {\n                throw new NullPointerException();\n            }\n            this.diskUsage = diskUsage;\n            File directory = file.getParentFile();\n            Files.makeDir(directory);\n            boolean completed = file.exists();\n            this.file = completed ? file : new File(file.getParentFile(), file.getName() + TEMP_POSTFIX);\n            this.dataFile = new RandomAccessFile(this.file, completed ? \"r\" : \"rw\");\n        } catch (IOException e) {\n            throw new ProxyCacheException(\"Error using file \" + file + \" as disc cache\", e);\n        }\n    }\n\n    @Override\n    public synchronized long available() throws ProxyCacheException {\n        try {\n            return (int) dataFile.length();\n        } catch (IOException e) {\n            throw new ProxyCacheException(\"Error reading length of file \" + file, e);\n        }\n    }\n\n    @Override\n    public synchronized int read(byte[] buffer, long offset, int length) throws ProxyCacheException {\n        try {\n            dataFile.seek(offset);\n            return dataFile.read(buffer, 0, length);\n        } catch (IOException e) {","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/CarGuo/GSYVideoPlayer/blob/e5d74d3aa9d7fb1393a879e33ee380f8f41354f1/gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/file/FileCache.java#L21-L57","documentation":"FileCache.available() returns (int) dataFile.length(); RandomAccessFile.length() rarely throws, but if the file was closed or the fd became invalid (file deleted underneath, volume unmounted), the IOException is wrapped as ProxyCacheException('Error reading length of file <path>'). It means the cache file's file descriptor is no longer usable.","triggerScenarios":"The cached file (or its temp .download) was deleted while FileCache still held it - e.g. by the cache-cleaner of the proxy itself in another thread, a user storage-cleaner app, or the file living on removed external storage - and then the player requested available()/read().","commonSituations":"SD-card cache dirs on devices where the card is ejected; 'cleaner' apps wiping cache mid-playback; a misconfigured maxCacheSize causing the LRU trim to evict the file currently being read.","solutions":["Point the proxy cache at app-internal storage that third parties cannot wipe","Set maxCacheSize generously enough that the file in active use is not evicted; or fork to skip evicting the newest file","On this error, evict the specific entry (clearCache for url) and restart playback so a fresh FileCache is built","Avoid external removable storage for the cache directory"],"exampleFix":"// before - LRU may evict the in-use file\nnew Builder(ctx).maxCacheSize(64 * 1024 * 1024).build();\n\n// after - retry path that clears the broken entry and restarts\ncatch (ProxyCacheException e) {\n    proxyCacheServer.getHostCacheDb?? // n/a; instead:\n    player.release();\n    new File(cacheDir, md5(url) + \".download\").delete();\n    player.setUp(proxyCacheServer.getProxyUrl(url), true, headers);\n}","handlingStrategy":"try-catch","validationCode":"if (!cacheFile.exists() || !cacheFile.canRead()) {\n    // fd target vanished; purge entry before reading\n    cacheFile.delete();\n}","typeGuard":null,"tryCatchPattern":"try { long avail = fileCache.available(); }\ncatch (ProxyCacheException e) {\n    if (String.valueOf(e.getMessage()).contains(\"Error reading length\")) {\n        purgeEntryAndRestartPlayback(url); // rebuild FileCache\n    } else throw e;\n}","preventionTips":["Keep cache files on internal storage safe from cleaner apps","Size the LRU cap so in-use files are not evicted","Never share cache files with a second downloader"],"tags":["io","file-descriptor","eviction","storage","proxy-cache"],"backgroundTag":null,"analyzedSha":"e5d74d3aa9d7fb1393a879e33ee380f8f41354f1","analyzedAt":"2026-08-14T11:56:11.997Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}