{"record":{"id":"84410e25953694e9","repo":"CarGuo/GSYVideoPlayer","slug":"reading-source-sourceinfo-url-is-interrupted","errorCode":null,"errorMessage":"Reading source ${sourceInfo.url} is interrupted","messagePattern":"Reading source (.+?) is interrupted","errorType":"exception","errorClass":"InterruptedProxyCacheException","httpStatus":null,"severity":"error","filePath":"gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpUrlSource.java","lineNumber":138,"sourceCode":"                    \"https://github.com/danikula/AndroidVideoCache/issues.\";\n                throw new RuntimeException(message, e);\n            } catch (ArrayIndexOutOfBoundsException e) {\n                HttpProxyCacheDebuger.printfError(\"Error closing connection correctly. Should happen only on Android L. \" +\n                    \"If anybody know how to fix it, please visit https://github.com/danikula/AndroidVideoCache/issues/88. \" +\n                    \"Until good solution is not know, just ignore this issue :(\", e);\n            }\n        }\n    }\n\n    @Override\n    public int read(byte[] buffer) throws ProxyCacheException {\n        if (inputStream == null) {\n            throw new ProxyCacheException(\"Error reading data from \" + sourceInfo.url + \": connection is absent!\");\n        }\n        try {\n            return inputStream.read(buffer, 0, buffer.length);\n        } catch (InterruptedIOException e) {\n            throw new InterruptedProxyCacheException(\"Reading source \" + sourceInfo.url + \" is interrupted\", e);\n        } catch (IOException e) {\n            throw new ProxyCacheException(\"Error reading data from \" + sourceInfo.url, e);\n        }\n    }\n\n    private void fetchContentInfo() throws ProxyCacheException {\n        HttpURLConnection urlConnection = null;\n        InputStream inputStream = null;\n        try {\n            urlConnection = openConnection(0, 10000);\n            long length = getContentLength(urlConnection);\n            String mime = urlConnection.getContentType();\n            inputStream = urlConnection.getInputStream();\n            this.sourceInfo = new SourceInfo(sourceInfo.url, length, mime);\n            this.sourceInfoStorage.put(sourceInfo.url, sourceInfo);\n        } catch (IOException e) {\n            HttpProxyCacheDebuger.printfError(\"Error fetching info from \" + sourceInfo.url, e);\n        } finally {","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/CarGuo/GSYVideoPlayer/blob/e5d74d3aa9d7fb1393a879e33ee380f8f41354f1/gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpUrlSource.java#L120-L156","documentation":"HttpUrlSource.read's generic IOException branch (after InterruptedIOException was checked first): any mid-stream IO failure - connection reset, premature EOF handling, TLS abort - is wrapped as ProxyCacheException('Error reading data from <url>'). It means the origin connection broke while the proxy was piping bytes to the cache/player.","triggerScenarios":"The ProxyCache source-reader thread is pumping bytes into FileCache when the socket dies: server closed the connection, mobile network switched (WiFi<->cellular), or the CDN reset long-lived streams. Also thrown when read() is called with inputStream == null ('connection is absent!' variant inside the same method family).","commonSituations":"Network switching during playback; aggressive CDN idle resets; NAT timeouts on paused streams; flaky carrier connections. Pausing a video for minutes then resuming commonly triggers it.","solutions":["Catch ProxyCacheException in the player error path and trigger a smart retry: recreate the proxy url (getProxyUrl continues from cached offset) and resume playback at the saved position","Implement onNetworkChanged handling: on connectivity regain, restart playback from last position","Use a HeaderInjector/timeout tuning so slow origins are not cut off","Do not disable proxy caching for this - the cache actually makes resume-after-error cheap since only the uncached tail is re-fetched"],"exampleFix":"// before\n@Override public void onPlayError(String url, Throwable t) { finish(); }\n\n// after - resume from cached data\n@Override public void onPlayError(String url, Throwable t) {\n    if (t instanceof ProxyCacheException || t.getCause() instanceof ProxyCacheException) {\n        long pos = player.getCurrentPositionWhenPlaying();\n        player.release();\n        player.setUp(proxyCacheServer.getProxyUrl(url), true, cacheHeaders);\n        player.startPlayLogic();\n        player.onPrepareReusable(pos);\n    }\n}","handlingStrategy":"retry","validationCode":"// check connectivity before resuming playback\nConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);\nNetworkInfo ni = cm.getActiveNetworkInfo();\nif (ni == null || !ni.isConnected()) { /* wait for network instead of retrying */ }","typeGuard":null,"tryCatchPattern":"catch (ProxyCacheException e) {\n    if (e instanceof InterruptedProxyCacheException) return; // shutdown, ignore\n    resumePlaybackFromCachedOffset(url, lastPosition); // rebuild proxy url, seek to lastPosition\n}","preventionTips":["Save playback position on error and resume via getProxyUrl (cached prefix is reused)","Listen for connectivity changes to restart after a network switch","Do not disable proxy caching on this error - its cache makes resume cheap"],"tags":["network","io","connection-reset","proxy-cache","retry"],"backgroundTag":null,"analyzedSha":"e5d74d3aa9d7fb1393a879e33ee380f8f41354f1","analyzedAt":"2026-08-14T11:56:11.997Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}