jdx/mise · error
server returned inconsistent partial content
Error message
server returned inconsistent partial content
What it means
On resume, the server's 206 response is validated against the recorded partial-download state: the range must start at the saved offset, end at the saved total size, the content length must match, and any ETag/validator must match. If any check fails, mise restarts once without resume; if the retry is also inconsistent, it aborts with this error rather than appending bytes from a changed or different file.
Source
Thrown at src/http.rs:1043
}
restarted_without_resume = true;
continue;
};
let validator = response_validator(resp.headers());
let response_length_matches = resp
.content_length()
.is_none_or(|length| length == end - start + 1);
if start != offset
|| end + 1 != total
|| !response_length_matches
|| state.total_size.is_some_and(|expected| expected != total)
|| validator
.as_ref()
.is_some_and(|value| !value.matches(&state.validator))
{
partial.clear()?;
if restarted_without_resume {
bail!("server returned inconsistent partial content");
}
restarted_without_resume = true;
continue;
}
// Keep the filename associated with the bytes already on disk.
// A redirect target may change between requests even when the
// server accepts the validator and Range header. Replacing the
// stored hint could make the completed bytes use a different
// archive format than the response that started the partial.
let effective_filename = state.effective_filename;
let validator = validator.unwrap_or(state.validator);
(
offset,
Some(total),
Some(validator),
true,
effective_filename,
)View on GitHub (pinned to afd2eddd3a)
Solutions
- Delete the partial download and its state file so mise fetches the file from scratch.
- Verify the URL still points at the same artifact; re-pin the tool version if the remote was updated.
- Retry later if the server is mid-rollout and serving inconsistent content across requests.
Example fix
// before: stale .part from an older release being resumed # nothing to edit — stale partial state // after: clear partial state and reinstall rm -rf "$(mise cache_dir)/downloads"/<artifact>*.part*; mise install node@22
Defensive patterns
Strategy: fallback
Validate before calling
if let Some((etag, total)) = saved_state {
let head = client.head(url).send().await?;
if head.etag() != Some(&etag) || head.content_length() != Some(total) {
delete_partial(); // remote changed; resume would be invalid
}
} Try / catch
if let Err(e) = download().await {
if e.to_string().contains("inconsistent partial content") {
delete_partial_download();
download().await?; // restart clean
} else { return Err(e); }
} Prevention
- Pin tool versions so the remote artifact at a URL does not change under you.
- Delete old .part files after long gaps before retrying an install.
- Prefer mirrors with immutable, content-addressed artifact URLs.
When it happens
Trigger: Resuming a .part download where the remote file changed between sessions (new ETag/Last-Modified), the server returns a range not starting at the requested offset, the total size differs from the recorded one, or the Content-Length does not match end-start+1 — and a fresh restart hits the same mismatch.
Common situations: Resuming a download after the upstream released a new version at the same URL; a load-balanced pool serving different artifacts; an interrupted download left stale for days before retrying.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- should not be called for system tool
- HTTP download timed out after {} for {} (attempt {}, {} byte
- server returned an invalid Content-Range response
- Got HTML instead of text from {}
- cannot encode #{value.class} as JSON
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/de023c8acd737093.
Report an issue: GitHub.