{"record":{"id":"78a8581ac32dc557","repo":"CarGuo/GSYVideoPlayer","slug":"error-renaming-file-s-to-s-for-completion","errorCode":null,"errorMessage":"Error renaming file %s to %s for completion!","messagePattern":"Error renaming file (.+?) to (.+?) for completion!","errorType":"exception","errorClass":"ProxyCacheException","httpStatus":null,"severity":"error","filePath":"gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/file/FileCache.java","lineNumber":98,"sourceCode":"            dataFile.close();\n            diskUsage.touch(file);\n        } catch (IOException e) {\n            throw new ProxyCacheException(\"Error closing file \" + file, e);\n        }\n    }\n\n    @Override\n    public synchronized void complete() throws ProxyCacheException {\n        if (isCompleted()) {\n            return;\n        }\n\n        close();\n        String fileName = file.getName().substring(0, file.getName().length() - TEMP_POSTFIX.length());\n        File completedFile = new File(file.getParentFile(), fileName);\n        boolean renamed = file.renameTo(completedFile);\n        if (!renamed) {\n            throw new ProxyCacheException(\"Error renaming file \" + file + \" to \" + completedFile + \" for completion!\");\n        }\n        file = completedFile;\n        try {\n            dataFile = new RandomAccessFile(file, \"r\");\n            diskUsage.touch(file);\n        } catch (IOException e) {\n            throw new ProxyCacheException(\"Error opening \" + file + \" as disc cache\", e);\n        }\n    }\n\n    @Override\n    public synchronized boolean isCompleted() {\n        return !isTempFile(file);\n    }\n\n    /**\n     * Returns file to be used fo caching. It may as original file passed in constructor as some temp file for not completed cache.\n     *","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/CarGuo/GSYVideoPlayer/blob/e5d74d3aa9d7fb1393a879e33ee380f8f41354f1/gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/file/FileCache.java#L80-L116","documentation":"After a successful rename, FileCache.complete reopens the finished file read-only (new RandomAccessFile(file, \"r')) and touches DiskUsage. IOException here becomes ProxyCacheException('Error opening <file> as disc cache'). The file exists and is renamed, but can no longer be opened for reading - permissions changed, file deleted instantly by a cleaner, or fs errors.","triggerScenarios":"Immediately after rename, something deletes or locks the completed file (eviction thread from another proxy instance, cleaner app), or the directory's permissions prevent reopen. Rare; requires a race or external interference in the microseconds between rename and reopen.","commonSituations":"Two cache instances trimming the same folder concurrently; storage cleaner racing the proxy; almost never seen in single-instance, internal-storage setups.","solutions":["Enforce one proxy instance per cache directory (singleton pattern)","On the error, purge the url's cache entry and let the next playback re-download","Use internal, app-private cache storage immune to external cleaners","If persistent, check device storage health / remount loops"],"exampleFix":"// before - fatal\ncatch (ProxyCacheException e) { throw e; }\n\n// after - purge entry and degrade to no-cache playback\ncatch (ProxyCacheException e) {\n    Log.w(TAG, \"reopening completed cache failed, purging entry\", e);\n    new File(cacheDir, md5(url)).delete();\n    playDirectWithoutCache(url);\n}","handlingStrategy":"fallback","validationCode":"File f = new File(cacheDir, md5(url));\nif (!f.exists() || !f.canRead()) { /* purge entry, degrade to no-cache */ f.delete(); }","typeGuard":null,"tryCatchPattern":"catch (ProxyCacheException e) {\n    if (String.valueOf(e.getMessage()).contains(\"Error opening\") && e.getMessage().contains(\"as disc cache\")) {\n        purgeEntry(url); playDirect(url);\n    } else throw e;\n}","preventionTips":["Ensure a single cache owner process","Purge and re-cache on reopen failure instead of retrying the broken file","Use internal storage to avoid external cleaners racing the rename"],"tags":["io","race-condition","storage","proxy-cache"],"backgroundTag":null,"analyzedSha":"e5d74d3aa9d7fb1393a879e33ee380f8f41354f1","analyzedAt":"2026-08-14T11:56:11.997Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}