jdx/mise · error · eyre::Report
cannot relocate {}: replacement for {} does not fit ({} > {}
Error message
cannot relocate {}: replacement for {} does not fit ({} > {} bytes) What it means
Bottle binaries embed fixed-size placeholder paths (the build machine's prefix, e.g. /usr/local or /opt/homebrew) that mise rewrites in place during relocation, because Mach-O/ELF offsets cannot grow. A replacement must fit into the original slot — the placeholder string plus its trailing run of NULs, minus one NUL kept as terminator. If the real prefix path is longer than the slot, in-place patching is impossible and relocation aborts with the byte counts.
Source
Thrown at src/system/packages/brew/relocate.rs:176
// keep); find the end at the next NUL
let str_end = content[start..]
.iter()
.position(|&b| b == 0)
.map(|p| start + p)
.unwrap_or(content.len());
// available slot: the string plus the run of NULs after it,
// minus one NUL that must remain as terminator
let slot_end = content[str_end..]
.iter()
.position(|&b| b != 0)
.map(|p| str_end + p)
.unwrap_or(content.len());
let old = content[start..str_end].to_vec();
let mut new = r.value.clone();
new.extend_from_slice(&old[r.placeholder.len()..]);
let slot = slot_end.saturating_sub(start);
if new.len() + 1 > slot {
bail!(
"cannot relocate {}: replacement for {} does not fit ({} > {} bytes)",
path.display(),
String::from_utf8_lossy(r.placeholder),
new.len() + 1,
slot,
);
}
content[start..start + new.len()].copy_from_slice(&new);
for b in &mut content[start + new.len()..slot_end] {
*b = 0;
}
changed = true;
search_from = start + new.len();
}
}
Ok(changed)
}
View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Use the default (shorter) mise install prefix instead of a deeply nested custom one
- Shorten the path: shallower HOME, shorter username, or a symlinked prefix such as /opt/mise pointing at the real location
- Install that package with native Homebrew (its real paths match the placeholders) or via another backend
Defensive patterns
Strategy: validation
Validate before calling
# estimate before installing: placeholder slots are sized for short prefixes like /usr/local
PREFIX="$(mise data-dir)/brew/..." # the real target path baked into binaries
echo "target prefix length: ${#PREFIX} bytes (placeholders are ~10-15 bytes); keep it short or symlink /opt/mise -> $PREFIX" Prevention
- Use mise's default install locations — they are sized to fit bottle placeholders
- Avoid deeply nested HOME/XDG paths or very long usernames on machines using brew packages
- If a custom long path is unavoidable, symlink a short prefix like /opt/mise to it
When it happens
Trigger: Relocating a file where the placeholder must be replaced by a much longer real path: the check new.len() + 1 > slot fails. Long usernames, deeply nested HOME/XDG dirs, or a custom mise data dir push the target path past the placeholder's slot size.
Common situations: Installing into /home/very-long-username/.local/share/mise/... where the path exceeds the placeholder by dozens of bytes; organizations redirecting HOME or XDG_DATA_HOME to long canonical paths in automount environments.
Related errors
- cannot relocate {}: rpath must grow but the dynamic string t
- cannot relocate {}: not enough padding to grow load commands
- unexpected ELF e_phentsize {e_phentsize}
- ELF uses PN_XNUM program header counts
- malformed Mach-O in {}
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/a311b9256c630d41.
Report an issue: GitHub.