CarGuo/GSYVideoPlayer · critical · IllegalArgumentException

Subtitle url is empty

Error message

Subtitle url is empty

What it means

HttpProxyCacheServer's constructor binds a ServerSocket to the loopback proxy host with a OS-assigned port, installs an IgnoreHostProxySelector, and starts a wait-connections thread gated by a CountDownLatch. If binding/opening fails (IOException) or the start signal is interrupted before the server thread comes up, it shuts down the socket processor and throws IllegalStateException('Error starting local proxy server').

Source

Thrown at gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/subtitle/GSYSubtitleLoader.java:90

    public void cancelCurrent() {
        if (currentTask != null) {
            currentTask.cancel(true);
            currentTask = null;
        }
    }

    public void release() {
        cancelCurrent();
        executorService.shutdownNow();
    }

    private String read(Context context, GSYSubtitleSource source) throws Exception {
        InputStream inputStream = null;
        HttpURLConnection connection = null;
        try {
            String url = source.getUrl();
            if (TextUtils.isEmpty(url)) {
                throw new IllegalArgumentException("Subtitle url is empty");
            }
            Uri uri = Uri.parse(url);
            String scheme = uri.getScheme();
            if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) {
                connection = (HttpURLConnection) new URL(url).openConnection();
                connection.setInstanceFollowRedirects(true);
                connection.setConnectTimeout(15000);
                connection.setReadTimeout(15000);
                for (Map.Entry<String, String> entry : source.getHeaders().entrySet()) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
                inputStream = new BufferedInputStream(connection.getInputStream());
            } else if ("file".equalsIgnoreCase(scheme)) {
                inputStream = new BufferedInputStream(new FileInputStream(new File(uri.getPath())));
            } else if (TextUtils.isEmpty(scheme)) {
                inputStream = new BufferedInputStream(new FileInputStream(new File(url)));
            } else {
                inputStream = new BufferedInputStream(context.getContentResolver().openInputStream(uri));

View on GitHub (pinned to e5d74d3aa9)

Solutions

  1. Keep a single application-scoped HttpProxyCacheServer singleton (static or in Application) and reuse it
  2. Ensure the old instance is fully released/unregistered before creating another
  3. Retry construction once after a brief delay - transient fd exhaustion often clears
  4. If a VPN/adaptive-network tool blocks loopback, test on another device and report incompatibility

Example fix

// before (per-activity - leaks sockets)
public void play(String url) {
    HttpProxyCacheServer proxy = new HttpProxyCacheServer.Builder(this).build();
    ...
}

// after - app-wide singleton
public class App extends Application {
    private static HttpProxyCacheServer proxy;
    public static HttpProxyCacheServer getProxy(Context ctx) {
        if (proxy == null) proxy = new HttpProxyCacheServer.Builder(ctx).build();
        return proxy;
    }
}
Defensive patterns

Strategy: fallback

Validate before calling

if (proxy != null && proxy.isAlive()) { /* reuse */ } else { proxy = new HttpProxyCacheServer.Builder(app).build(); }

Try / catch

try {
    proxy = new HttpProxyCacheServer.Builder(app).build();
} catch (IllegalStateException e) {
    // transient socket/fd exhaustion: play direct url without proxy this session
    playUrl(originalUrl); 
}

Prevention

When it happens

Trigger: Constructing new HttpProxyCacheServer.Builder(context).build() when the loopback interface is unavailable, the process hit its file-descriptor/socket limit, or the waitConnectionThread was interrupted during startup (startSignal.await threw InterruptedException).

Common situations: Creating a new HttpProxyCacheServer per video/fragment instead of keeping one app-wide singleton (socket exhaustion); devices with networking disabled/airplane-mode edge cases affecting InetAddress.getByName(PROXY_HOST); heavy fd usage from leaked players; some emulators/VPN configurations interfering with loopback binding.

Related errors


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