{"record":{"id":"d82ac7ab2cb61206","repo":"CarGuo/GSYVideoPlayer","slug":"too-many-redirects-redirectcount","errorCode":null,"errorMessage":"Too many redirects: ${redirectCount}","messagePattern":"Too many redirects: (.+?)","errorType":"exception","errorClass":"ProxyCacheException","httpStatus":null,"severity":"error","filePath":"gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpUrlSource.java","lineNumber":213,"sourceCode":"                    }\n                    connection.setRequestProperty(\"Range\", \"bytes=\" + ofr + \"-\");\n                } else {\n                    connection.setRequestProperty(\"Range\", \"bytes=\" + (int)offset + \"-\");\n                }\n            }\n            if (timeout > 0) {\n                connection.setConnectTimeout(timeout);\n                connection.setReadTimeout(timeout);\n            }\n            int code = connection.getResponseCode();\n            redirected = code == HTTP_MOVED_PERM || code == HTTP_MOVED_TEMP || code == HTTP_SEE_OTHER;\n            if (redirected) {\n                url = connection.getHeaderField(\"Location\");\n                redirectCount++;\n                connection.disconnect();\n            }\n            if (redirectCount > MAX_REDIRECTS) {\n                throw new ProxyCacheException(\"Too many redirects: \" + redirectCount);\n            }\n        } while (redirected);\n        return connection;\n    }\n\n    private void injectCustomHeaders(HttpURLConnection connection, String url) {\n        Map<String, String> extraHeaders = headerInjector.addHeaders(url);\n        if (extraHeaders == null) {\n            return;\n        }\n        HttpProxyCacheDebuger.printfError(\"****** injectCustomHeaders ****** :\" + extraHeaders.size());\n        for (Map.Entry<String, String> header : extraHeaders.entrySet()) {\n            connection.setRequestProperty(header.getKey(), header.getValue());\n        }\n    }\n\n    public synchronized String getMime() throws ProxyCacheException {\n        if (TextUtils.isEmpty(sourceInfo.mime)) {","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/CarGuo/GSYVideoPlayer/blob/e5d74d3aa9d7fb1393a879e33ee380f8f41354f1/gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpUrlSource.java#L195-L231","documentation":"ProxyCache.readSource loop counts consecutive source read failures; before each (re)attempt it calls checkReadSourceErrorsCount, and because MAX_READ_SOURCE_ATTEMPTS is 1, the very first read error after a retry trigger throws ProxyCacheException('Error reading source 1 times'). This deliberately aborts the cache-filling loop instead of hammering a broken origin.","triggerScenarios":"The source reader thread gets a ProxyCacheException from HttpUrlSource.read (network drop, connection reset) while filling FileCache; on the next loop iteration the error count (already >= 1) trips this guard and the caching session is terminated.","commonSituations":"Any mid-stream network failure while proxy caching - same root causes as error 6/7 (network switch, server reset). This is the terminal aggregate exception the player's onError often receives after the underlying read failure.","solutions":["Fix the underlying network/source error (see HttpUrlSource read errors) - this exception is a symptom, not the cause","Wrap playback start in a retry that rebuilds the proxy url and resumes from cached offset","Check disk space: a full disk during caching surfaces as read/append errors then this","If you fork the library and want resilience, raise MAX_READ_SOURCE_ATTEMPTS and add backoff"],"exampleFix":"// before - propagate and kill playback\ncatch (Exception e) { player.stop(); }\n\n// after - bounded resume attempt using already-cached bytes\nint attempts = 0;\nwhile (attempts++ < 2) {\n    try { startOrResume(proxyCacheServer.getProxyUrl(url)); break; }\n    catch (Exception e) { Log.w(TAG, \"cache read failed, attempt \" + attempts, e); }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch (ProxyCacheException e) {\n    if (String.valueOf(e.getMessage()).startsWith(\"Error reading source\")) {\n        // symptom of an earlier read failure: bounded resume attempt\n        if (attempts++ < 2) resumeFromCachedOffset(url, position);\n        else playDirect(url);\n    } else throw e;\n}","preventionTips":["Fix the root network error rather than catching this aggregate","Check disk space before caching on low-storage devices","Implement a bounded retry with backoff instead of endless restarts"],"tags":["network","retry","proxy-cache","resilience"],"backgroundTag":null,"analyzedSha":"e5d74d3aa9d7fb1393a879e33ee380f8f41354f1","analyzedAt":"2026-08-14T11:56:11.997Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}