lingochamp/FileDownloader · error · RuntimeException

connection is null when findEtag

Error message

connection is null when findEtag

What it means

findEtag extracts the 'Etag' response header from an HTTP connection used for resumable downloads. It throws a RuntimeException if the connection is null, since a null connection is an internal programming error — a valid connection is required to read the Etag for breakpoint-resume validation.

Solutions

  1. Ensure the connection is non-null before calling: check the result of the connect/creation step and handle failures before reading headers.
  2. If using a custom connection factory, never return null — throw a descriptive IOException instead.
  3. Guard the call site with if (connection != null) and treat null as a retryable network failure.

Example fix

// before
String etag = FileDownloadUtils.findEtag(id, connection); // connection may be null

// after
if (connection == null) {
    throw new FileDownloadNetworkException("connection failed, cannot read Etag");
}
String etag = FileDownloadUtils.findEtag(id, connection);
Defensive patterns

Strategy: validation

Validate before calling

if (connection == null) {
    throw new IOException("download connection not established; cannot read Etag");
}
String etag = FileDownloadUtils.findEtag(id, connection);

Try / catch

try {
    etag = FileDownloadUtils.findEtag(id, connection);
} catch (RuntimeException e) {
    // treat as network failure; retry or restart task without resume
}

Prevention

When it happens

Trigger: Calling FileDownloadUtils.findEtag(id, null) with a connection that failed to be created (e.g. FileDownloadConnection creation failed after connect) or was never assigned.

Common situations: Custom DownloadConnection implementation returning null on error; network layer failure swallowed upstream so the null connection propagates to findEtag; unit tests passing null stubs.

Related errors


AI-assisted analysis of lingochamp/FileDownloader@6237a8cac1 (2026-09-08). Data as JSON: /api/errors/accbd3d25ed4e745. Report an issue: GitHub.

Appendix: source

Thrown at library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java:550

    public static boolean checkPermission(String permission) {
        final int perm = FileDownloadHelper.getAppContext()
                .checkCallingOrSelfPermission(permission);
        return perm == PackageManager.PERMISSION_GRANTED;
    }

    public static long convertContentLengthString(String s) {
        if (s == null) return -1;
        try {
            return Long.parseLong(s);
        } catch (NumberFormatException e) {
            return -1;
        }
    }

    public static String findEtag(final int id, FileDownloadConnection connection) {
        if (connection == null) {
            throw new RuntimeException("connection is null when findEtag");
        }

        final String newEtag = connection.getResponseHeaderField("Etag");

        if (FileDownloadLog.NEED_LOG) {
            FileDownloadLog.d(FileDownloadUtils.class, "etag find %s for task(%d)", newEtag, id);
        }

        return newEtag;
    }

    // accept range is effect by  response code and Accept-Ranges header field.
    public static boolean isAcceptRange(int responseCode, FileDownloadConnection connection) {
        if (responseCode == HttpURLConnection.HTTP_PARTIAL
                || responseCode == FileDownloadConnection.RESPONSE_CODE_FROM_OFFSET) return true;

        final String acceptRanges = connection.getResponseHeaderField("Accept-Ranges");
        return "bytes".equals(acceptRanges);

View on GitHub (pinned to 6237a8cac1)