jdx/mise · error

cannot relocate : replacement for does not fit ( > bytes)

Error message

cannot relocate {}: replacement for {} does not fit ({} > {} bytes)

What it means

Binary relocation rewrites embedded absolute paths (e.g. the brew prefix) in place inside binaries. In-place replacement can only grow a string into the NUL padding that follows it in its slot; when the replacement (new value + remaining suffix + terminator) exceeds the available slot bytes, replace_in_binary bails, because overwriting past the slot would corrupt adjacent data in the binary.

Solutions

  1. Use a prefix no longer than the bottle's original install path (default /opt/homebrew on macOS, /home/linuxbrew/.linuxbrew on Linux)
  2. Set MISE_SYSTEM_BREW_PREFIX to the standard short location and place brew there, then re-apply the package
  3. Reinstall/re-pour the affected formula so the bottle is re-extracted and relocated fresh (a partially relocated keg must be removed first)

Example fix

# before
export MISE_SYSTEM_BREW_PREFIX=/very/long/nested/path/to/my/super/long/brew/prefix
# after
export MISE_SYSTEM_BREW_PREFIX=/home/linuxbrew/.linuxbrew
Defensive patterns

Strategy: validation

Validate before calling

defaultPrefix=$(grep -ao '/[a-z/]*\.linuxbrew\|[a-z/]*brew' one-binary-from-bottle | head -1)
if [ ${#MISE_SYSTEM_BREW_PREFIX} -gt ${#defaultPrefix} ]; then
  echo "custom prefix longer than bottle's build prefix — relocation may not fit"
fi

Prevention

When it happens

Trigger: replace_in_binary (called by relocate_keg_with_replacements during pour) finds a placeholder occurrence whose replacement value is longer than the C-string slot (string + trailing NUL run minus one terminator) — e.g. relocating a bottle built with a short install path (like /opt/brew) into a much longer custom MISE_SYSTEM_BREW_PREFIX.

Common situations: Choosing an unusually long brew prefix (deep directory names, long usernames) when the bottle was built for the short default /home/linuxbrew/.linuxbrew or /opt/homebrew; relocation between prefixes of very different lengths.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/a311b9256c630d41. Report an issue: GitHub.

Appendix: source

Thrown at src/system/packages/brew/relocate.rs:178

            // 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 533346cc37)