{"record":{"id":"1212cc26b354cdd5","repo":"jdx/mise","slug":"no-dynamic-linker-found-for-ld-homebrew-bottles-require","errorCode":null,"errorMessage":"no dynamic linker found for {ld} — Homebrew bottles require glibc (musl-based distros are unsupported)","messagePattern":"no dynamic linker found for (.+?) — Homebrew bottles require glibc \\(musl-based distros are unsupported\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/prefix.rs","lineNumber":115,"sourceCode":"        return Ok(());\n    }\n    if ld.exists() {\n        return Ok(()); // valid symlink or file already in place\n    }\n    if ld.symlink_metadata().is_ok() {\n        crate::file::remove_file(&ld)?; // dangling symlink\n    }\n    let host_loader = [\n        \"/lib64/ld-linux-x86-64.so.2\",\n        \"/lib/ld-linux-aarch64.so.1\",\n        \"/lib64/ld-linux-aarch64.so.1\",\n    ]\n    .iter()\n    .map(Path::new)\n    .find(|p| p.exists())\n    .map(Path::to_path_buf);\n    let Some(target) = host_loader else {\n        bail!(\n            \"no dynamic linker found for {} — Homebrew bottles require glibc (musl-based \\\n             distros are unsupported)\",\n            ld.display()\n        );\n    };\n    crate::file::make_symlink(&target, &ld)?;\n    Ok(())\n}\n\nfn writable(path: &Path) -> bool {\n    // root can write regardless of owner — and `sudo mise` must never treat\n    // a user-owned prefix as broken and chown it to root\n    if nix::unistd::geteuid().is_root() {\n        return path.exists();\n    }\n    !matches!(\n        path.metadata()\n            .map(|m| std::os::unix::fs::MetadataExt::uid(&m)),","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/prefix.rs#L97-L133","documentation":"On Linux, Homebrew bottles are glibc-linked and mise's prefix setup must provide a dynamic linker (ld.so) inside the brew prefix. setup_linux_runtime searches for a host glibc loader at the standard paths (/lib64/ld-linux-x86-64.so.2, /lib/ld-linux-aarch64.so.1, etc.) and bails when none exists, since musl-based distros (Alpine, musl Void) cannot run glibc bottles without a brewed glibc.","triggerScenarios":"Running brew package installation on Linux where no host glibc dynamic linker exists at the checked paths — typically a musl-based distribution (Alpine Linux) or a heavily stripped container without glibc and no brewed glibc keg.","commonSituations":"Alpine/musl containers or CI images; distroless golang/alpine base images where someone enabled the brew backend; minimal chroots lacking /lib64.","solutions":["Install glibc on the host (e.g. Alpine's `apk add glibc` via the gcompat/glibc packages or use a glibc-based base image like debian/ubuntu)","Let mise brew a glibc keg first so the loader can be taken from Cellar/glibc (ensure the glibc formula can be installed)","Use a non-brew backend for packages on musl systems (apk-compatible tools, or github:/cargo: backends)"],"exampleFix":"// Dockerfile before\nFROM alpine:3.20\n// after\nFROM debian:bookworm-slim  # or apk add --allow-untrusted glibc on alpine","handlingStrategy":"validation","validationCode":"[ -x /lib64/ld-linux-x86-64.so.2 ] || [ -x /lib/ld-linux-aarch64.so.1 ] \\\n  || echo \"no glibc loader — brew bottles unsupported on this (musl?) system\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use glibc-based base images (debian, ubuntu) when enabling the brew backend in containers","On Alpine, install glibc before using brew packages, or avoid the brew backend entirely","Detect musl early (`ldd --version | grep -q musl`) and pick alternative backends"],"tags":["brew","linux","glibc","musl"],"backgroundTag":"unsupported-platform","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"}