jdx/mise · error · eyre::Report
cannot relocate {}: rpath must grow but the dynamic string t
Error message
cannot relocate {}: rpath must grow but the dynamic string table could not be located What it means
When an rpath replacement no longer fits in its original slot, the patchelf-style strategy appends a new PT_LOAD with a rebuilt dynamic string table — which requires locating DT_STRTAB, DT_STRSZ, and the file offset of the strsz value in PT_DYNAMIC. If any is missing (or the strtab vaddr maps to no file offset), the grow path is impossible and the pour fails for that file.
Source
Thrown at src/system/packages/brew/elf.rs:304
&& let (Some(old), Some(new)) = (&old_rpath, &new_rpath_str)
&& let (Some(st), Some(rp)) = (strtab_off, rpath_strtab_off)
{
let start = st + rp as usize;
content[start..start + new.len()].copy_from_slice(new.as_bytes());
for b in &mut content[start + new.len()..start + old.len()] {
*b = 0;
}
}
if interp_in_place && rpath_in_place {
return Ok(true);
}
// grow: append a new PT_LOAD holding the relocated program header table
// plus whichever strings no longer fit (patchelf's approach)
let move_interp = !interp_in_place;
let move_dynstr = !rpath_in_place;
if move_dynstr && (strtab_off.is_none() || strsz.is_none() || strsz_val_off.is_none()) {
bail!(
"cannot relocate {}: rpath must grow but the dynamic string table \
could not be located",
path.display()
);
}
let align = phdrs
.iter()
.filter(|p| p.p_type == PT_LOAD)
.map(|p| p.p_align)
.max()
.unwrap_or(0x1000)
.max(0x10000); // covers 4K/16K/64K runtime page sizes
let new_off = round_up(content.len() as u64, align);
let max_vaddr_end = phdrs
.iter()
.filter(|p| p.p_type == PT_LOAD)
.map(|p| p.p_vaddr + p.p_memsz)View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Install the brew prefix at a path no longer than the bottle's build prefix (/home/linuxbrew/.linuxbrew, or a similarly short path) so strings fit in place
- Verify the binary with readelf -d — if DT_STRTAB/DT_STRSZ are genuinely absent, report the bottle upstream
- Fall back to pouring that formula with upstream Homebrew's PatchELF-based flow
Example fix
# before: long prefix forces rpath to grow mise settings brew.prefix ~/dev/tools/sandbox/homebrew # 33 chars > 20-char placeholder # after: short prefix keeps replacements in place mise settings brew.prefix /home/linuxbrew/.linuxbrew # same length as build prefix
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight the grow-path prerequisites: a dynamic section exposing
// DT_STRTAB and DT_STRSZ, with the strtab vaddr inside a PT_LOAD.
fn grow_path_possible(content: &[u8]) -> bool {
// parse PT_DYNAMIC entries; require DT_STRTAB (5) and DT_STRSZ (10)
// both present before DT_NULL (0), and strtab vaddr mappable to an offset
parse_dynamic_has(content, &[5, 10]) // simplified predicate
} Try / catch
// Fail the pour with an actionable message including the path, and suggest
// a shorter prefix (the practical fix when rpath must grow).
match elf::patch(&mut content, &opts, &path) {
Err(e) if e.to_string().contains("dynamic string table") => {
return Err(e.wrap_err("rpath needs to grow; try a brew prefix no longer than /home/linuxbrew/.linuxbrew"))
}
other => other?,
} Prevention
- Install the brew prefix at a path length at or below the bottle build prefix so string growth never triggers
- When supporting arbitrary prefixes, pre-scan binaries for DT_STRTAB/DT_STRSZ before committing to the pour
When it happens
Trigger: elf::patch grow path: move_dynstr && (strtab_off.is_none() || strsz.is_none() || strsz_val_off.is_none()). Happens when a Linux bottle binary has DT_RPATH/DT_RUNPATH but no usable DT_STRTAB/DT_STRSZ entries before DT_NULL, or its vaddr does not fall inside a PT_LOAD — combined with a target prefix longer than the '@@HOMEBREW_PREFIX@@' placeholder so in-place replacement cannot fit.
Common situations: Installing the brew prefix under a long path (deep home directory) so every replacement string grows; binaries produced by exotic linkers (musl custom flags, BOLT-rewritten, prelinked) with unusual dynamic sections.
Related errors
- unexpected ELF e_phentsize {e_phentsize}
- ELF uses PN_XNUM program header counts
- cannot relocate {}: not enough padding to grow load commands
- cannot relocate {}: replacement for {} does not fit ({} > {}
- malformed Mach-O in {}
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/bef08889dd36e7a1.
Report an issue: GitHub.