How to check if a derivation builds in nix?

I would like to create a derivation that depends on a lot of other derivations, that are allowed to fail to build. So I need a way for my large derivation to not fail if one of its dependencies fails to build.

something like:

map (
  dependency:
    if builtins.tryEval dependency then
      <include dependency>
   else <dont include dependency>
) dependencyList

Problem is, tryEval doesn’t work here. Any Ideas?

On one hand I’m wondering if there’s not a better solution for your specific problem, so it would be nice to get some more concrete information on what exactly you need this for.

But, there’s also testers.testBuildFailure which probably helps you here: Nixpkgs 23.11 manual | Nix & NixOS

1 Like

I’m trying to archive, that a playlist derivation doesn’t fail if some of the song derivations fail.

(im confused is this a reply to infinisil? the other reply has a small reply badge above, but this doesn’t, still it shows 2 replies on infinisils answer)

I’m trying to archive, that a playlist derivation doesn’t fail if some of the song derivations fail.

I’m trying to figure out why this doesn’t work

{runCommand}: drv:
import "${
  runCommand "buildSucceeds" {} ''
    if nix-build ${drv.drvPath}; then
        echo true >$out
    else
        echo false >$out
    fi
  ''
}"

But when trying to get the log output (after removing the import "${ & }") with nix-repl> :log ... or nix log i just get:

error: cannot open connection to remote store 'daemon': error: reading from file: Connection reset by peer

I have the feeling that I’m doing something illegal…

It works, but it’s horrible, I have to literally build every package twice:

{
  writeText,
  coreutils,
  buildPackages,
  stdenv,
}: drv:
import "${drv.overrideAttrs (orig: {
  builder = buildPackages.bash;
  args =
    [
      (
        writeText "testBuildSuccess" ''
          # Stricter bash
          set -eu

          # Run the original builder
          ("$@" 2>&1) | ${coreutils}/bin/tee $TMPDIR/testBuildFailure.log |
            while IFS= read -r ln; do
              echo "original builder: $ln"
            done

          # Get the exit status
          r=$ {PIPESTATUS[0]}
          #  ^ remove the space here, markdown doesn't understand string interpolation escaping

          ${coreutils}/bin/rm -rf $out
          if [[ $r = 0 ]]; then
            echo "true" >$out
          else
            echo "false" >$out
          fi
        ''
      )
      orig.realBuilder or stdenv.shell
    ]
    ++ orig.args
    or [
      "-e"
      (orig.builder
        or (writeText "default-builder" ''
          if [ -f .attrs.sh ]; then
              . .attrs.sh
          fi
          source $stdenv/setup
          genericBuild
        ''))
    ];
})}"

There is another solution: don’t let the small derivations (the dependencies) fail.
If I handle errors in the small derivations, so instead of failing, they would complain loudly and result in an empty directory, or an empty file, I could then handle (or ignore) that in the large derivation (that depends on the small ones).

The downside is, if a derivation fails to build because of some unexpected error, like scdl failing randomly or scdl or yt-dlp failing because of country restrictions, nix considers these as successfully built and won’t build them again. But that’s an entirely different problem, that only arises because I disabled the nix sandbox.