exportReferencesGraph of a storepath of a drv does not match the closure of it's context #1039

Open
opened 2025-11-18 06:23:19 +00:00 by bacchanalia · 2 comments
Member

Consider the following code:

let    
  nixpkgs = builtins.fetchTarball {    
    url = "https://github.com/NixOS/nixpkgs/archive/4c8cdd5b1a630e8f72c9dd9bf582b1afb3127d2c.tar.gz";    
    sha256 = "sha256-LBVOyaH6NFzQ3X/c6vfMZ9k4SV2ofhpxeL9YnhHNJQQ=";    
  };    
  pkgs = import nixpkgs {};    
    
  pkg = pkgs.hello;    
  outPath = builtins.unsafeDiscardStringContext pkg.outPath;    
  drvPath = builtins.unsafeDiscardStringContext pkg.drvPath;    
    
  drvStorePath = builtins.appendContext "${drvPath}" { ${drvPath} = { path = true; }; };    
    
in with pkgs; stdenv.mkDerivation {    
    name = "references-graph.json";    
    __structuredAttrs = true;    
    exportReferencesGraph = {    
      graph = [ drvStorePath ];    
    };    
    PATH = "${coreutils}/bin";    
    builder = writeText "references-graph-builder" ''    
      mkdir $out    
      cp .attrs.json $out    
    '';    
}    

One would expect references-graph.json to contain the closure of the context of drvStorePath, that is the closure of the derivation without it's outputs, matching the output of nix-store -qR /nix/store/lh2pxynz5f9yccmlhx7xhgh7w9r8ifc2-hello-2.12.1.drv.

Instead it produces that same referencesGraph as if drvStorePath = pkg.drvPath (which has the context { ${drvPath} = { allOutputs = true; }; }), and the build will fail if anything in the closure of the outputs does not already exists in the store due to the mismatch with the context.

There does not seem to be a current way to use exportReferencesGraph to interrogate the closure of just a derivation and not it's outputs.

Consider the following code: ```nix let nixpkgs = builtins.fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/4c8cdd5b1a630e8f72c9dd9bf582b1afb3127d2c.tar.gz"; sha256 = "sha256-LBVOyaH6NFzQ3X/c6vfMZ9k4SV2ofhpxeL9YnhHNJQQ="; }; pkgs = import nixpkgs {}; pkg = pkgs.hello; outPath = builtins.unsafeDiscardStringContext pkg.outPath; drvPath = builtins.unsafeDiscardStringContext pkg.drvPath; drvStorePath = builtins.appendContext "${drvPath}" { ${drvPath} = { path = true; }; }; in with pkgs; stdenv.mkDerivation { name = "references-graph.json"; __structuredAttrs = true; exportReferencesGraph = { graph = [ drvStorePath ]; }; PATH = "${coreutils}/bin"; builder = writeText "references-graph-builder" '' mkdir $out cp .attrs.json $out ''; } ``` One would expect `references-graph.json` to contain the closure of the context of `drvStorePath`, that is the closure of the derivation without it's outputs, matching the output of `nix-store -qR /nix/store/lh2pxynz5f9yccmlhx7xhgh7w9r8ifc2-hello-2.12.1.drv`. Instead it produces that same referencesGraph as if `drvStorePath = pkg.drvPath` (which has the context `{ ${drvPath} = { allOutputs = true; }; }`), and the build will fail if anything in the closure of the outputs does not already exists in the store due to the mismatch with the context. There does not seem to be a current way to use `exportReferencesGraph` to interrogate the closure of just a derivation and not it's outputs.
Owner

context is completely discarded by the time the reference graph generation runs, only store paths remain known. since only store paths are known we cannot encode how to handle derivations multiple ways depending on user wishes, instead it always uses the old (and removed) interpretation of drv paths as "that and all outputs".

There does not seem to be a current way to use exportReferencesGraph to interrogate the closure of just a derivation and not it's outputs.

correct, we'd have to add a new primitive to do that

context is completely discarded by the time the reference graph generation runs, only store paths remain known. since only store paths are known we cannot encode how to handle derivations multiple ways depending on user wishes, instead it always uses the old (*and removed*) interpretation of drv paths as "that and all outputs". > There does not seem to be a current way to use exportReferencesGraph to interrogate the closure of just a derivation and not it's outputs. correct, we'd have to add a new primitive to do that
Author
Member

I think the fact that the build can fail indicates that this is in fact a bug. It's not really due to the unsafeDiscardString context because you can produce the the same string/context with builtins.storePath. I do take your point that since the issue is on the realization side, it would need a new construct in order to not change the meaning of existing derivations.

I think the fact that the build can fail indicates that this is in fact a bug. It's not really due to the unsafeDiscardString context because you can produce the the same string/context with builtins.storePath. I do take your point that since the issue is on the realization side, it would need a new construct in order to not change the meaning of existing derivations.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lix-project/lix#1039
No description provided.