{"record":{"id":"b1cf881ec73719a3","repo":"CarGuo/GSYVideoPlayer","slug":"error-starting-local-proxy-server","errorCode":null,"errorMessage":"Error starting local proxy server","messagePattern":"Error starting local proxy server","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java","lineNumber":86,"sourceCode":"        this(new Builder(context).buildConfig());\n    }\n\n    private HttpProxyCacheServer(Config config) {\n        this.config = checkNotNull(config);\n        try {\n            InetAddress inetAddress = InetAddress.getByName(PROXY_HOST);\n            this.serverSocket = new ServerSocket(0, 8, inetAddress);\n            this.port = serverSocket.getLocalPort();\n            IgnoreHostProxySelector.install(PROXY_HOST, port);\n            CountDownLatch startSignal = new CountDownLatch(1);\n            this.waitConnectionThread = new Thread(new WaitRequestsRunnable(startSignal));\n            this.waitConnectionThread.start();\n            startSignal.await(); // freeze thread, wait for server starts\n            this.pinger = new Pinger(PROXY_HOST, port);\n            HttpProxyCacheDebuger.printfLog(\"Proxy cache server started. Is it alive? \" + isAlive());\n        } catch (IOException | InterruptedException e) {\n            socketProcessor.shutdown();\n            throw new IllegalStateException(\"Error starting local proxy server\", e);\n        }\n    }\n\n    /**\n     * Returns url that wrap original url and should be used for client (MediaPlayer, ExoPlayer, etc).\n     * <p>\n     * If file for this url is fully cached (it means method {@link #isCached(String)} returns {@code true})\n     * then file:// uri to cached file will be returned.\n     * <p>\n     * Calling this method has same effect as calling {@link #getProxyUrl(String, boolean)} with 2nd parameter set to {@code true}.\n     *\n     * @param url a url to file that should be cached.\n     * @return a wrapped by proxy url if file is not fully cached or url pointed to cache file otherwise.\n     */\n    public String getProxyUrl(String url) {\n        return getProxyUrl(url, true);\n    }\n","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/CarGuo/GSYVideoPlayer/blob/e5d74d3aa9d7fb1393a879e33ee380f8f41354f1/gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java#L68-L104","documentation":"HttpUrlSource.open(offset) opens an HttpURLConnection (following manual redirect handling), reads content type/length, and stores SourceInfo. Any IOException during connect, getInputStream, or header parsing becomes a ProxyCacheException naming the url and offset. This is the proxy's main 'could not reach the origin server for this byte range' error.","triggerScenarios":"ProxyCache requests a range (offset > 0 after a seek) and the origin returns connection reset / 416 / DNS failure / TLS error; openConnection follows more than MAX_REDIRECTS(5) hops is handled separately, but socket timeouts and unreachable hosts land here; an invalid Content-Length header (Long.parseLong) also throws here.","commonSituations":"Expired signed CDN URLs (token in query string no longer valid when the proxy re-requests ranges); server dropping keep-alive connections causing connection reset on seek; device behind a captive portal; server not supporting Range requests while the proxy opens with an offset; malformed Content-Length header (non-numeric).","solutions":["Refresh the playback URL (re-fetch signed token URL) before seeking or on error and restart playback via GSYVideoPlayer","Implement a custom HttpUrlSource with a HeaderInjector that injects fresh auth tokens/referer for each request","Add retry-once logic around player start in onError of GSYVideoViewBuilder","Verify the URL supports Range requests (Accept-Ranges header) or use an origin that does"],"exampleFix":"// before\nproxyCacheServer.getProxyUrl(expiredSignedUrl);\n\n// after - inject fresh headers per request via HeaderInjector\npublic class AuthHeaderInjector implements HeaderInjector {\n    @Override\n    public Map<String, String> addHeaders(String url) {\n        Map<String, String> h = new HashMap<>();\n        h.put(\"Authorization\", \"Bearer \" + TokenStore.current());\n        return h;\n    }\n}\nnew HttpProxyCacheServer.Builder(context).headerInjector(new AuthHeaderInjector()).build();","handlingStrategy":"retry","validationCode":"// cheap pre-flight before handing url to the proxy\nHttpURLConnection c = (HttpURLConnection) new URL(url).openConnection();\nc.setRequestMethod(\"HEAD\");\nint code = c.getResponseCode(); // 2xx expected; catch IOException before proxy does","typeGuard":null,"tryCatchPattern":"try { play(proxy.getProxyUrl(url)); }\ncatch (ProxyCacheException e) {\n    if (String.valueOf(e.getMessage()).contains(\"Error opening connection\")) {\n        url = refreshSignedUrl(); play(proxy.getProxyUrl(url)); // one retry with fresh url\n    } else throw e;\n}","preventionTips":["Refresh signed/expiring urls right before playback, not at list-load time","Inject auth headers via HeaderInjector instead of baking tokens into urls","Confirm the origin supports range requests"],"tags":["network","http","range-request","proxy-cache","signed-url"],"backgroundTag":null,"analyzedSha":"e5d74d3aa9d7fb1393a879e33ee380f8f41354f1","analyzedAt":"2026-08-14T11:56:11.997Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}