{"record":{"id":"324d9246646eed28","repo":"jdx/mise","slug":"cannot-relocate-not-enough-padding-to-grow-loa","errorCode":null,"errorMessage":"cannot relocate {}: not enough padding to grow load commands ({} > {} bytes)","messagePattern":"cannot relocate (.+?): not enough padding to grow load commands \\((.+?) > (.+?) bytes\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/macho.rs","lineNumber":152,"sourceCode":"                    let new_cmdsize = (str_off + new.len() + 1).div_ceil(8) * 8;\n                    let mut rebuilt = bytes[..str_off].to_vec();\n                    rebuilt.extend_from_slice(&new);\n                    rebuilt.resize(new_cmdsize.max(cmdsize), 0);\n                    let len = rebuilt.len() as u32;\n                    rebuilt[4..8].copy_from_slice(&len.to_le_bytes());\n                    bytes = rebuilt;\n                    changed = true;\n                }\n            }\n        }\n        commands.push(bytes);\n    }\n    if !changed {\n        return Ok(false);\n    }\n    let new_sizeofcmds: usize = commands.iter().map(|c| c.len()).sum();\n    if HEADER_SIZE_64 + new_sizeofcmds > first_data {\n        bail!(\n            \"cannot relocate {}: not enough padding to grow load commands ({} > {} bytes)\",\n            path.display(),\n            HEADER_SIZE_64 + new_sizeofcmds,\n            first_data,\n        );\n    }\n    let mut out = Vec::with_capacity(new_sizeofcmds);\n    for c in &commands {\n        out.extend_from_slice(c);\n    }\n    // zero everything from the header to the first data byte, then lay the\n    // table down — leaves old table bytes cleanly erased\n    slice[HEADER_SIZE_64..first_data].fill(0);\n    slice[HEADER_SIZE_64..HEADER_SIZE_64 + out.len()].copy_from_slice(&out);\n    slice[20..24].copy_from_slice(&(new_sizeofcmds as u32).to_le_bytes());\n    Ok(true)\n}\n","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/macho.rs#L134-L170","documentation":"Thrown when the rewritten load-command table grows larger than the padding available before the first section data byte. Mach-O patching can only grow commands into padding between sizeofcmds and the first section — there is no room to shift section data, so relocation is refused rather than corrupting the binary.","triggerScenarios":"After rebuilding commands with expanded path strings (e.g. longer install names/prefixes), HEADER_SIZE_64 + new_sizeofcmds > first_data triggers the bail. Called by patch when path replacements lengthen LC_LOAD_DYLIB/LC_ID_DYLIB/LC_RPATH strings beyond available padding.","commonSituations":"Relocating brew bottles to a prefix longer than the original; replacing short paths with much longer custom paths; binaries with little or no inter-table padding; many dylib entries each growing slightly.","solutions":["Choose a target prefix that is the same length or shorter than the original path.","Pad the original install names at build time (e.g. via `-headerpad_max_install_names` ld flag) so future rewrites fit.","Rebuild the formula/binary from source with the desired paths instead of binary-patching.","Fall back to symlinking the original path structure so no rewrite is needed."],"exampleFix":"// before: patch to a longer prefix, fails\npatch(&path, &[(\"/opt/homebrew/opt\", \"/very/long/custom/prefix/opt\")])?;\n// after: keep length compatible or rebuild\nlet new_prefix = \"/short/pfx\";\nassert!(new_prefix.len() <= \"/opt/homebrew\".len());\npatch(&path, &[(\"/opt/homebrew\", new_prefix)])?;","handlingStrategy":"validation","validationCode":"fn rewrite_fits(old_prefix: &str, new_prefix: &str) -> bool {\n    new_prefix.len() <= old_prefix.len()\n}","typeGuard":null,"tryCatchPattern":"match patch(&path, &replacements) {\n    Err(e) if e.to_string().contains(\"not enough padding\") => {\n        eprintln!(\"prefix too long for binary patching; rebuilding from source\");\n        // fall back to `brew install --build-from-source`\n    }\n    other => other?,\n}","preventionTips":["Build with `-headerpad_max_install_names` so binaries have slack for rewrites.","Keep relocation prefixes length-equal or shorter than the original.","Prefer source builds over binary patching for long custom prefixes.","Test relocation on a copy of the binary before applying to the install tree."],"tags":["macos","binary-patching","relocation"],"backgroundTag":"value-out-of-range","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"}