{"record":{"id":"6eb0c23e95e5ea6a","repo":"CarGuo/GSYVideoPlayer","slug":"error-reading-d-bytes-with-offset-d-from-file-d","errorCode":null,"errorMessage":"Error reading %d bytes with offset %d from file[%d bytes] to buffer[%d bytes]","messagePattern":"Error reading (.+?) bytes with offset (.+?) from file\\[(.+?) bytes\\] to buffer\\[(.+?) bytes\\]","errorType":"exception","errorClass":"ProxyCacheException","httpStatus":null,"severity":"warning","filePath":"gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/file/FileCache.java","lineNumber":59,"sourceCode":"    }\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) {\n            String format = \"Error reading %d bytes with offset %d from file[%d bytes] to buffer[%d bytes]\";\n            throw new ProxyCacheException(String.format(format, length, offset, available(), buffer.length), e);\n        }\n    }\n\n    @Override\n    public synchronized void append(byte[] data, int length) throws ProxyCacheException {\n        try {\n            if (isCompleted()) {\n                throw new ProxyCacheException(\"Error append cache: cache file \" + file + \" is completed!\");\n            }\n            dataFile.seek(available());\n            dataFile.write(data, 0, length);\n        } catch (IOException e) {\n            String format = \"Error writing %d bytes to %s from buffer with size %d\";\n            throw new ProxyCacheException(String.format(format, length, dataFile, data.length), e);\n        }\n    }\n\n    @Override","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/CarGuo/GSYVideoPlayer/blob/e5d74d3aa9d7fb1393a879e33ee380f8f41354f1/gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/file/FileCache.java#L41-L77","documentation":"FileCache.append refuses to write once isCompleted() is true (file renamed from .download to final, opened read-only). Throwing here guards the invariant that a completed cache file is immutable; it fires when the source reader tries to add bytes after completion was already signaled - usually a race or a double-pump in the caching loop.","triggerScenarios":"Two paths append to the same FileCache after complete() ran: e.g. ProxyCache.readSource retrying after completion, or two proxy requests for the same url sharing a cache entry where the second writer outlives the first's completion.","commonSituations":"Concurrent playback of the same url in two players with a shared proxy; race between the completion path (close + rename) and a lingering reader thread after an error/retry cycle. Rare in normal single-player usage.","solutions":["Reuse one HttpProxyCacheServer and one player per url; avoid starting two concurrent playbacks of the same url during a retry storm","On this error, simply discard it in logs - the file is already fully cached and usable","If it recurs in your fork, add a state check (isCompleted) before entering the append path in your reader loop"],"exampleFix":"// before - unconditional append\nfileCache.append(data, read);\n\n// after - guard\nif (!fileCache.isCompleted()) {\n    fileCache.append(data, read);\n}","handlingStrategy":"type-guard","validationCode":"if (!fileCache.isCompleted()) {\n    fileCache.append(data, read);\n}","typeGuard":"boolean canAppend = !fileCache.isCompleted(); // guard before append","tryCatchPattern":"catch (ProxyCacheException e) {\n    if (String.valueOf(e.getMessage()).contains(\"is completed\")) {\n        // benign: file already fully cached, drop the write\n        Log.d(TAG, \"append after completion ignored\");\n    } else throw e;\n}","preventionTips":["One player/proxy session per url at a time","Check isCompleted() before writing","Treat this specific message as benign log noise"],"tags":["race-condition","state","proxy-cache","io"],"backgroundTag":null,"analyzedSha":"e5d74d3aa9d7fb1393a879e33ee380f8f41354f1","analyzedAt":"2026-08-14T11:56:11.997Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}