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
- Register a security provider: Security.addProvider(new BouncyCastleProvider()) or restore the default AndroidOpenSSL/BouncyCastle provider.
- Inspect Security.getProviders() at startup to find which provider registration is missing and fix the runtime configuration.
- 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
- Verify Security.getProviders() on custom/hardened devices before release.
- Avoid shading or stripping JCA provider classes in ProGuard/R8 rules.
- Test filename generation on all supported device profiles.
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
- Huh, UTF-8 should be supported?
- If you start the task manually, it means this task doesn't…
- This task is running
- This task is dirty to restart, If you want to reuse this…
- the provided mPath[ ] is invalid, can't find its directory
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)