CarGuo/GSYVideoPlayer · error · IllegalStateException

Error starting local proxy server

Error message

Error starting local proxy server

What it means

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.

Source

Thrown at gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java:86

        this(new Builder(context).buildConfig());
    }

    private HttpProxyCacheServer(Config config) {
        this.config = checkNotNull(config);
        try {
            InetAddress inetAddress = InetAddress.getByName(PROXY_HOST);
            this.serverSocket = new ServerSocket(0, 8, inetAddress);
            this.port = serverSocket.getLocalPort();
            IgnoreHostProxySelector.install(PROXY_HOST, port);
            CountDownLatch startSignal = new CountDownLatch(1);
            this.waitConnectionThread = new Thread(new WaitRequestsRunnable(startSignal));
            this.waitConnectionThread.start();
            startSignal.await(); // freeze thread, wait for server starts
            this.pinger = new Pinger(PROXY_HOST, port);
            HttpProxyCacheDebuger.printfLog("Proxy cache server started. Is it alive? " + isAlive());
        } catch (IOException | InterruptedException e) {
            socketProcessor.shutdown();
            throw new IllegalStateException("Error starting local proxy server", e);
        }
    }

    /**
     * Returns url that wrap original url and should be used for client (MediaPlayer, ExoPlayer, etc).
     * <p>
     * If file for this url is fully cached (it means method {@link #isCached(String)} returns {@code true})
     * then file:// uri to cached file will be returned.
     * <p>
     * Calling this method has same effect as calling {@link #getProxyUrl(String, boolean)} with 2nd parameter set to {@code true}.
     *
     * @param url a url to file that should be cached.
     * @return a wrapped by proxy url if file is not fully cached or url pointed to cache file otherwise.
     */
    public String getProxyUrl(String url) {
        return getProxyUrl(url, true);
    }

View on GitHub (pinned to e5d74d3aa9)

Solutions

  1. Refresh the playback URL (re-fetch signed token URL) before seeking or on error and restart playback via GSYVideoPlayer
  2. Implement a custom HttpUrlSource with a HeaderInjector that injects fresh auth tokens/referer for each request
  3. Add retry-once logic around player start in onError of GSYVideoViewBuilder
  4. Verify the URL supports Range requests (Accept-Ranges header) or use an origin that does

Example fix

// before
proxyCacheServer.getProxyUrl(expiredSignedUrl);

// after - inject fresh headers per request via HeaderInjector
public class AuthHeaderInjector implements HeaderInjector {
    @Override
    public Map<String, String> addHeaders(String url) {
        Map<String, String> h = new HashMap<>();
        h.put("Authorization", "Bearer " + TokenStore.current());
        return h;
    }
}
new HttpProxyCacheServer.Builder(context).headerInjector(new AuthHeaderInjector()).build();
Defensive patterns

Strategy: retry

Validate before calling

// cheap pre-flight before handing url to the proxy
HttpURLConnection c = (HttpURLConnection) new URL(url).openConnection();
c.setRequestMethod("HEAD");
int code = c.getResponseCode(); // 2xx expected; catch IOException before proxy does

Try / catch

try { play(proxy.getProxyUrl(url)); }
catch (ProxyCacheException e) {
    if (String.valueOf(e.getMessage()).contains("Error opening connection")) {
        url = refreshSignedUrl(); play(proxy.getProxyUrl(url)); // one retry with fresh url
    } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of CarGuo/GSYVideoPlayer@e5d74d3aa9 (2026-08-14). Data as JSON: /api/errors/b1cf881ec73719a3. Report an issue: GitHub.