lingochamp/FileDownloader · error · RuntimeException

Huh, MD5 should be supported?

Error message

Huh, MD5 should be supported?

What it means

md5() computes an MD5 digest of a UTF-8 string and wraps any NoSuchAlgorithmException in a RuntimeException. MD5 is guaranteed by the JCA spec on every JVM/Android runtime, so hitting this means the platform's security provider list is broken. The thrown message is intentionally rhetorical since the case should be impossible.

Solutions

  1. Register a security provider: Security.addProvider(new BouncyCastleProvider()) or restore the default AndroidOpenSSL/BouncyCastle provider.
  2. Inspect Security.getProviders() at startup to find which provider registration is missing and fix the runtime configuration.
  3. As a last resort, catch the RuntimeException and fall back to a non-MD5 filename scheme (e.g. Base64-encoded URL).

Example fix

// before
String name = FileDownloadUtils.generateFileName(url); // throws if MD5 missing

// after
if (Security.getProvider("BC") == null) {
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
String name = FileDownloadUtils.generateFileName(url);
Defensive patterns

Strategy: try-catch

Validate before calling

try {
    MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
    Security.addProvider(new BouncyCastleProvider());
}

Try / catch

try {
    String name = FileDownloadUtils.generateFileName(url);
} catch (RuntimeException e) {
    Log.e("FileDownloader", "MD5 unavailable on this runtime", e);
    name = Base64.encodeToString(url.getBytes(), Base64.URL_SAFE);
}

Prevention

When it happens

Trigger: MessageDigest.getInstance("MD5") throws NoSuchAlgorithmException while generating a download filename hash — only possible when the JVM's crypto providers are misconfigured or stripped (e.g. custom runtime without the default provider).

Common situations: Highly customized/hardened Android builds or embedded JVMs with a reduced security provider set; classpath/shading conflicts that remove the default provider registration.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

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

     * @param url  The downloading URL.
     * @param path If {@code pathAsDirectory} is {@code true}, {@code path} would be the absolute
     *             directory to place the file;
     *             If {@code pathAsDirectory} is {@code false}, {@code path} would be the absolute
     *             file path.
     * @return The download id.
     */
    public static int generateId(final String url, final String path,
                                 final boolean pathAsDirectory) {
        return CustomComponentHolder.getImpl().getIdGeneratorInstance()
                .generateId(url, path, pathAsDirectory);
    }

    public static String md5(String string) {
        byte[] hash;
        try {
            hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Huh, MD5 should be supported?", e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Huh, UTF-8 should be supported?", e);
        }

        StringBuilder hex = new StringBuilder(hash.length * 2);
        for (byte b : hash) {
            if ((b & 0xFF) < 0x10) hex.append("0");
            hex.append(Integer.toHexString(b & 0xFF));
        }
        return hex.toString();
    }


    public static String getStack() {
        return getStack(true);
    }

    public static String getStack(final boolean printLine) {

View on GitHub (pinned to 6237a8cac1)