{"record":{"id":"bef08889dd36e7a1","repo":"jdx/mise","slug":"cannot-relocate-rpath-must-grow-but-the-dynami","errorCode":null,"errorMessage":"cannot relocate {}: rpath must grow but the dynamic string table could not be located","messagePattern":"cannot relocate (.+?): rpath must grow but the dynamic string table could not be located","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/elf.rs","lineNumber":304,"sourceCode":"        && let (Some(old), Some(new)) = (&old_rpath, &new_rpath_str)\n        && let (Some(st), Some(rp)) = (strtab_off, rpath_strtab_off)\n    {\n        let start = st + rp as usize;\n        content[start..start + new.len()].copy_from_slice(new.as_bytes());\n        for b in &mut content[start + new.len()..start + old.len()] {\n            *b = 0;\n        }\n    }\n    if interp_in_place && rpath_in_place {\n        return Ok(true);\n    }\n\n    // grow: append a new PT_LOAD holding the relocated program header table\n    // plus whichever strings no longer fit (patchelf's approach)\n    let move_interp = !interp_in_place;\n    let move_dynstr = !rpath_in_place;\n    if move_dynstr && (strtab_off.is_none() || strsz.is_none() || strsz_val_off.is_none()) {\n        bail!(\n            \"cannot relocate {}: rpath must grow but the dynamic string table \\\n             could not be located\",\n            path.display()\n        );\n    }\n\n    let align = phdrs\n        .iter()\n        .filter(|p| p.p_type == PT_LOAD)\n        .map(|p| p.p_align)\n        .max()\n        .unwrap_or(0x1000)\n        .max(0x10000); // covers 4K/16K/64K runtime page sizes\n    let new_off = round_up(content.len() as u64, align);\n    let max_vaddr_end = phdrs\n        .iter()\n        .filter(|p| p.p_type == PT_LOAD)\n        .map(|p| p.p_vaddr + p.p_memsz)","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/elf.rs#L286-L322","documentation":"When patching an ELF's rpath, the new rpath usually fits in the existing dynamic string table slot. If it must grow, the patcher relocates the dynamic string table into a newly appended PT_LOAD — but that requires knowing the string table's file offset (strtab_off), size (strsz), and the file offset of the DT_STRSZ value to rewrite. If the PT_DYNAMIC segment did not yield those (e.g. missing DT_STRTAB/DT_STRSZ entries, or the strtab vaddr could not be mapped to a file offset), the relocation cannot proceed safely and patch bails.","triggerScenarios":"Calling elf::patch on a binary whose new rpath is longer than the old one (so it cannot be written in place) while the dynamic section lacks DT_STRTAB or DT_STRSZ entries, or the DT_STRTAB vaddr does not fall inside any PT_LOAD segment (so vaddr_to_offset returns None).","commonSituations":"Relinking an unusual binary (stripped, packed, or produced by a linker that omits DT_STRSZ or uses odd vaddr mapping) whose bottle placeholder rpath expands to a longer path under the new prefix; relocating binaries with malformed dynamic sections.","solutions":["Verify the binary's dynamic section is well formed (readelf -d shows DT_STRTAB and DT_STRSZ); rebuild the binary with the standard linker if not.","Re-download/re-extract the bottle — a corrupted dynamic section can hide DT entries.","For such binaries, fall back to patchelf (which handles more ELF variants) or skip relocation for that file."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// ensure dynamic string table metadata is present before requesting a grow-relocation\nlet dyn_ok = has_dt_strtab_and_strsz(&content); // scan PT_DYNAMIC for DT_STRTAB & DT_STRSZ\nlet will_grow = new_rpath_len > old_rpath_len;\nif will_grow && !dyn_ok { /* use patchelf fallback or skip */ }","typeGuard":null,"tryCatchPattern":"match elf::patch(&mut content, &opts, &path) {\n    Err(e) if e.to_string().contains(\"dynamic string table\") => {\n        warn!(\"{}: cannot grow rpath in place, falling back to patchelf\", path.display());\n    }\n    other => other?,\n}","preventionTips":["Only relocate binaries with well-formed PT_DYNAMIC segments (DT_STRTAB + DT_STRSZ present and mappable).","Prefer shorter install prefixes when bottling so new rpaths fit existing string slots.","Keep patchelf available as a fallback for exotic or packed binaries."],"tags":["elf","rpath","relocation","brew","linux"],"backgroundTag":"unsupported-operation","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}