diff --git a/hive-priv/src/main.rs b/hive-priv/src/main.rs index 0c5b9315..4f1dc185 100644 --- a/hive-priv/src/main.rs +++ b/hive-priv/src/main.rs @@ -816,10 +816,22 @@ async fn nix_build_toplevel(name: &str, mut writer: Option<&mut OwnedWriteHalf>) stderr_buf.lines().last().unwrap_or("").trim() ); } - let path = stdout_buf.trim(); - if path.is_empty() { - bail!("nix build {attr} produced no output path"); - } + // `--print-out-paths` prints one line *per output*, not one line + // total: `nix build --no-link --print-out-paths nixpkgs#openssl` + // prints two (`…-bin`, `…-man`). `config.system.build.toplevel` is + // single-output today, so this is one line in practice — but a bare + // `.trim()` would silently hand a multi-line string on to + // `--system-path` the day that ever changes, which is the same + // corrupted-argument failure this function exists to avoid. Require + // exactly one line and error otherwise, so a future multi-output + // attr fails loudly here instead of downstream in `nixos-container`. + let lines: Vec<&str> = stdout_buf.lines().collect(); + let [path] = lines[..] else { + bail!( + "nix build {attr} produced {} output path(s), expected exactly 1: {stdout_buf:?}", + lines.len() + ); + }; Ok(path.to_owned()) }