{"record":{"id":"8a4acf0546e2c69e","repo":"jdx/mise","slug":"mise-oci-requires-an-based-base-image-when-boo","errorCode":null,"errorMessage":"mise oci requires an {}-based base image when [bootstrap.packages] contains {} entries; `scratch` has no {} metadata","messagePattern":"mise oci requires an (.+?)-based base image when \\[bootstrap\\.packages\\] contains (.+?) entries; `scratch` has no (.+?) metadata","errorType":"exception","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/oci/packages.rs","lineNumber":73,"sourceCode":"    fn name(self) -> &'static str {\n        match self {\n            Self::Apk => \"apk\",\n            Self::Apt => \"apt\",\n        }\n    }\n}\n\npub fn build_system_packages_layer(\n    layout: &ImageLayout,\n    base_layers: &[Descriptor],\n    managers: &[ManagerPackages],\n    architecture: &str,\n) -> Result<Option<SystemPackagesLayer>> {\n    let Some((manager, requests)) = collect_package_requests(managers)? else {\n        return Ok(None);\n    };\n    if base_layers.is_empty() {\n        bail!(\n            \"mise oci requires an {}-based base image when [bootstrap.packages] contains {} \\\n             entries; `scratch` has no {} metadata\",\n            manager.name(),\n            manager.name(),\n            manager.name(),\n        );\n    }\n    validate_host_requirements(manager)?;\n\n    let td = TempDir::with_prefix(format!(\"mise-oci-{}-rootfs-\", manager.name())).wrap_err_with(\n        || {\n            format!(\n                \"creating temp rootfs for {} system packages\",\n                manager.name()\n            )\n        },\n    )?;\n    let rootfs = td.path().join(\"rootfs\");","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/oci/packages.rs#L55-L91","documentation":"When [bootstrap.packages] has entries, mise unpacks the base image and drives the matching host package manager (apk or apt) against that rootfs, so the base must actually be Alpine (apk) or Debian/Ubuntu (apt). With base_layers empty (a scratch base) there is no package-manager metadata to bootstrap from, and mise refuses instead of producing an image whose packages silently fail.","triggerScenarios":"mise oci build with base = \"scratch\" (or no base) combined with any [bootstrap.packages] entry; collect_package_requests found apk or apt requests but the base image contributed zero layers.","commonSituations":"Starting from a scratch/minimal image to shrink size, then adding packages; setting a distroless/empty base without realizing packages need an OS rootfs.","solutions":["Use a matching base image: alpine:3.20 for apk packages, debian:bookworm-slim / ubuntu:24.04 for apt packages.","Or drop [bootstrap.packages] and install nothing beyond mise-managed tools.","Verify the manager and base agree — apk entries on a debian base (or apt entries on alpine) are the adjacent mistake to check."],"exampleFix":"# before\n[bootstrap]\nbase = \"scratch\"\n  [bootstrap.packages]\n  curl = '*'\n\n# after\n[bootstrap]\nbase = \"alpine:3.20\"\n  [bootstrap.packages]\n  curl = '*'","handlingStrategy":"validation","validationCode":"import sys\nbase = config[\"bootstrap\"][\"base\"]\npkgs = config[\"bootstrap\"].get(\"packages\", {})\nif pkgs and (base is None or base == \"scratch\"):\n    sys.exit(\"[bootstrap.packages] requires an alpine (apk) or debian (apt) base image\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pair package families with their distro: apk -> alpine:*, apt -> debian/ubuntu.","Keep a matrix check in CI that validates base + packages combinations per mise.toml.","If image size drove you to scratch, use the distro -slim variants instead of dropping the base."],"tags":["oci","packages","base-image","scratch"],"backgroundTag":"base-image-requirement","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}