HMCL-dev/HMCL · error · java.io.IOException
Too much redirects
Error message
Too much redirects
What it means
FetchTask.downloadHttp() follows HTTP 3xx redirects manually and caps the chain at 20 hops to prevent infinite redirect loops. This IOException is thrown when the server has redirected more than 20 times, indicating a redirect loop or pathological configuration.
Solutions
- Open the URL in a browser or with curl -IL to inspect the redirect chain and find the loop
- Fix the target server/proxy configuration causing the loop, or use a direct final URL
- Authenticate properly if redirects are caused by missing cookies/credentials
- Clear any cached stale URL and use the canonical endpoint
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check redirect chain before downloading
HttpURLConnection c = (HttpURLConnection) uri.toURL().openConnection();
c.setInstanceFollowRedirects(false);
int hops = 0;
while (c.getResponseCode() >= 300 && c.getResponseCode() <= 308 && ++hops <= 25)
c = (HttpURLConnection) new URI(c.getHeaderField("Location")).toURL().openConnection();
if (hops > 20) throw new IllegalStateException("Redirect loop at " + uri); Try / catch
try {
fetchTask.run();
} catch (IOException e) {
if (e.getMessage().equals("Too much redirects")) useDirectUrlOrFallbackMirror();
else throw e;
} Prevention
- Resolve final URLs once and cache them instead of chasing redirects each run
- Curl -I suspect mirrors to detect loops early
- Avoid endpoints with auth-redirect bounce patterns
When it happens
Trigger: A URL whose redirect chain exceeds 20 hops — typically an infinite redirect loop (A -> B -> A), a misconfigured CDN, or cookie/auth issues causing repeated redirects to login and back.
Common situations: Mirror servers misconfigured with redirect loops; auth-gated endpoints bouncing between login and target; reverse proxies with conflicting rewrite rules.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Redirected to an empty location
- Too much redirects
- Failed to download theme background: HTTP
- https://api.minecraftservices.com/entitlements/mcstore
- https://api.minecraftservices.com/minecraft/profile
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/912e24be123c4dfb.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/task/FetchTask.java:352
headers.forEach(connection::setRequestProperty);
responseCode = connection.getResponseCode();
responseInfo = UrlResponseInfo.of(connection);
bmclapiHash = responseInfo.headers().firstValue("x-bmclapi-hash").orElse(null);
if (DigestUtils.isSha1Digest(bmclapiHash)) {
Optional<Path> cache = repository.checkExistentFile(null, "SHA-1", bmclapiHash);
if (cache.isPresent()) {
useCachedResult(cache.get());
LOG.info("Using cached file for " + NetworkUtils.dropQuery(uri));
return;
}
}
if (responseCode >= 300 && responseCode <= 308 && responseCode != 306 && responseCode != 304) {
if (redirects == null) {
redirects = new ArrayList<>();
} else if (redirects.size() >= 20) {
throw new IOException("Too much redirects");
}
String location = connection.getHeaderField("Location");
if (StringUtils.isBlank(location))
throw new IOException("Redirected to an empty location");
URI target = currentURI.resolve(NetworkUtils.encodeLocation(location));
redirects.add(target);
if (!NetworkUtils.isHttpUri(target))
throw new IOException("Redirected to not http URI: " + target);
currentURI = target;
} else {
keepConnection = true;
break;
}
} finally {View on GitHub (pinned to 24702dc5a0)