Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error: '/nix/store/.../flake.nix' must be an attribute set #3966

Open
nmattia opened this issue Aug 28, 2020 · 30 comments
Open

error: '/nix/store/.../flake.nix' must be an attribute set #3966

nmattia opened this issue Aug 28, 2020 · 30 comments
Labels
error-messages Confusing messages and better diagnostics flakes

Comments

@nmattia
Copy link
Contributor

nmattia commented Aug 28, 2020

Describe the bug

This flake.nix evaluates to an attribute set:

let
  foo = "bar";
in
{
  outputs = { self, nixpkgs }:
    {
      packages.x86_64-linux.devShell = nixpkgs.outputs.legacyPackages.x86_64-linux.hello;
    };
}

however nix develop (or nix build .#devShell) results in the following error:

$ nix develop
error: --- Error ------------------------------------------------------------------------------------ nix
file '/nix/store/wvlsr8s3nysj0pmgdl7ndggpxc8za87f-source/flake.nix' must be an attribute set
(use '--show-trace' to show detailed location information)

I can make nix happy by moving the let inside the outputs definition:

{
  outputs = { self, nixpkgs }:
    let
      foo = "bar";
    in
      {
        packages.x86_64-linux.devShell = nixpkgs.outputs.legacyPackages.x86_64-linux.hello;
      };
}

Expected behavior

I'm expecting the flake commands to allow top-level let bindings; but maybe that's on purpose to ensure the flake.nix stays as simple as possible?

nix-env --version output

nix-env (Nix) 2.4pre20200721_ff314f1

@nmattia nmattia added the bug label Aug 28, 2020
@zimbatm
Copy link
Member

zimbatm commented Aug 28, 2020

That's a strange limitation of how flakes are being evaluated. All of the data structures must be pretty much JSON-like data. The only place where more complex nix code is allowed is within the outputs function.

@edolstra
Copy link
Member

but maybe that's on purpose to ensure the flake.nix stays as simple as possible?

That's right. It ensures that a command like nix flake info doesn't have to evaluate an arbitrarily complex (and possibly non-terminating) Nix expression.

@nmattia
Copy link
Contributor Author

nmattia commented Aug 28, 2020

Ok I realize it's actually terribly picky, even thunks are forbidden (i.e. in an input's { url = "foo" + "bar"; }):

/tmp/tmp.7jJ3XRKbVP$ nix develop
error: --- Error ------------------------------------------------------------------------------------- nix
expected a string but got a thunk at /nix/store/4yiaxz02925lr1ssyir8nc7cs8dp7bf0-source/flake.nix:2:3
(use '--show-trace' to show detailed location information)

@jorsn
Copy link
Member

jorsn commented Sep 19, 2020

Why then use nix syntax if it is not nix? I'd say, either use a clearly defined subset of nix code, at best with another name and file ending (tnix – total nix) or the flake file shall be in a total language like plain json and the outputs attr refers to nix expressions, or dhall (but a comparatively complex new language).

If it looks like nix but isn't, to me it is confusing unexpected (”strange“ – zimbatm) behaviour.

Edit: Why not split the flake.nix into flake.json containing metadata and inputs and flake.nix/outputs.nix containing only the outputs function in real Nix lang?

@roberth
Copy link
Member

roberth commented Oct 10, 2020

I like the idea of specifying inputs and metadata in json. It's easier to work with for Nix itself and for external tools. With niv I often use niv update some-input -b feature-branch to test things out. nix flake doesn't have such a command and it'd be relatively hard to implement given the current flake format, because we don't have a way to write back modified asts without touching unmodified whitespace and comments.

I always used to think of the Nix language as a predictable element in an otherwise messy domain. Just a lazy evaluator that implicitly writes derivations. I don't think flakes need to change that.

@edolstra
Copy link
Member

I like the idea of specifying inputs and metadata in json.

The configs branch adds support for TOML as an alternative to flake.nix (1dc3f53). This allows the flake to be modified from the command line (e.g. 3632593).

nix flake doesn't have such a command

Well there is the --override-input flag. Since it only overwrites the lock file it doesn't have to deal with rewriting Nix expressions.

@edolstra edolstra added flakes error-messages Confusing messages and better diagnostics and removed bug labels Feb 9, 2021
@garbas garbas added this to the nix-2.4 milestone Feb 9, 2021
@malte-v
Copy link

malte-v commented Mar 7, 2021

Ugh. I just spent 8 hours writing a nix expression that dynamically generates flake inputs from an external registry and now I find out that it won't work. Is this limitation really such a great idea? If it's just there to improve the UX of nix flake info I would consider dropping it and allowing arbitrary Nix code in flakes.

@gytis-ivaskevicius
Copy link
Contributor

Would it be difficult to disallow most builtins instead? 🤔 This would more or less solve the problem with people writing complex expressions and would allow for some flexibility which would be neat.

@ggPeti
Copy link
Member

ggPeti commented Jun 7, 2021

Why are we trying to protect users from their own non-terminating nix expressions? On the other hand, why only in commands like nix flake info?

@jorsn
Copy link
Member

jorsn commented Jun 7, 2021 via email

@aszenz
Copy link

aszenz commented Jun 19, 2021

Ok I realize it's actually terribly picky, even thunks are forbidden (i.e. in an input's { url = "foo" + "bar"; }):

/tmp/tmp.7jJ3XRKbVP$ nix develop
error: --- Error ------------------------------------------------------------------------------------- nix
expected a string but got a thunk at /nix/store/4yiaxz02925lr1ssyir8nc7cs8dp7bf0-source/flake.nix:2:3
(use '--show-trace' to show detailed location information)

I just faced the same issue, very confusing to know I can't even concatenate strings inside flake inputs.
Maybe improving the error message would help, although i like the suggestion to just use json/toml

@edolstra edolstra modified the milestones: nix-2.4, nix-3.0 Sep 15, 2021
@kalhauge
Copy link

Can I add to this issue as well. I understand that limiting the computability of flakes are important, but I have some usecases where using expressions in flakes would be very useful.

For example, when all inputs comes from the same server. Here we have a Haskell flake that requires some specific versions of many packages from hackage:

{
  description = "My Picky Haskell Program";
  inputs = let
    hackage = name: {
      url = "https://hackage.haskell.org/package/${name}/${name}.tar.gz";
      flake = false;
    };
  in {
   package1 = hackage "package1-1.2.3";
   package2 = hackage "package2-3.2.1";
   ...
  };
  outputs = { self, package1, package2, ...}: 
    #...
  ;
}

Having to write out "http://hackage.haskell.org..." for every entry, is very error prone, and is hard to change. Being able to template the flakes inputs would really be a huge usability boon.

@con-f-use
Copy link

I agree, something like this would be very useful

{
  inputs = {
    foo = rec {
      type = "tarball";
      version = "1.2.3";
      url = "https://very.long/url/${version}/that/${version}/includes/${version}/a/lot/of/${version}"
    };
    # or:
    bar = let version = "1.2.3"; in { ... };
  };
}

@edolstra edolstra modified the milestones: nix-2.5, nix-2.6 Dec 10, 2021
@edolstra edolstra modified the milestones: nix-2.6, nix-2.7 Jan 21, 2022
@edolstra edolstra modified the milestones: nix-2.7, nix-2.8 Mar 3, 2022
@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/nix-flake-does-not-support-the-full-nix-language/27697/2

@edolstra edolstra modified the milestones: nix-2.15, nix-2.16, nix-2.17 May 26, 2023
@infinisil
Copy link
Member

Related: #4945

@tmillr
Copy link

tmillr commented Jun 15, 2023

Darn. I got stuck on this for a few hours also. Definitely could use a better error message at least, if things like top-level let aren't going to be allowed. I'm so glad I found this because I was just about to give up. The last thing I tried was builtins.isAttrs (import ./flake.nix) in the repl which returned true, which just makes the error file '/nix/store/*/flake.nix' must be an attribute set even more confusing.

@galenhuntington
Copy link

There is also a restriction on the form of outputs. This yields an error:

  outputs = import ./outputs.nix;
error: expected a function but got a thunk

I don't see why this limitation should be needed for nix flake info. However, it can be worked around by η-expanding:

  outputs = inputs: import ./outputs.nix inputs;

This works without issue.

@edolstra edolstra modified the milestones: nix-2.17, nix-2.18 Jul 24, 2023
@edolstra edolstra modified the milestones: nix-2.18, nix-2.19 Sep 20, 2023
@AleXoundOS
Copy link

AleXoundOS commented Nov 10, 2023

I think the main rationale behind using a subset of Nix for inputs is
to be able to define both inputs and outputs in a single file
(having completely different languages is out of question,
but one being a subset of another kinda works).

Letting computations in inputs would let the whole ecosystem bloat, be volatile, less readable, mostly losing the point of Nix flakes (for most users). At least some building blocks of the ecosystem should have fixed semantics, IMHO.

Though, I did encounter myself the input restrictions when trying to read inputs URLs using builtins.fromJSON, but realized it would be an overuse even if possible.

@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/programmatic-editing-of-flake-nix/35321/1

@dzmitry-lahoda
Copy link

dzmitry-lahoda commented Nov 12, 2023

hello. so there are 2 issues:

a. nix is not actually nix, but part of it like flake.json. so kind of flake.json flake.lock flake.nix trio.
b. bad errors/tooling for that nix not nix. but some turing decidable nix. turing decidable resource limited(stack/heap/references) nix is interesting subset feature.

either one fix of a or b will make else less important. will donate more to nix if a or be handled, as it seems good for increased adoption.

thank you

@AleXoundOS
Copy link

I'm sure tooling is the key.

@chekoopa
Copy link

chekoopa commented Jan 7, 2024

We develop a product which includes a server machine based on NixOS with some software modules (developed by us). As for servers, it also implies remote deployment and support.

So we somehow have survived with plain channels (by pinning them using a few forbidden techniques), but now I'm migrating all of this to flakes (because it refuses to build now).

The prime issue is dependency tracking. Every our software module is a separate folder in the monorepo, though they interconnect as dependencies (e.g. libraries). The first plan was just importing nixpkgs commit hash from a certain file. But as that's a very unsafe approach, now I'm brewing a single channel dispatcher to somehow provide a unified nixpkgs revision to all the modules in need.

Thus, yes, tooling is the key, but some unsafe-ty (at least possible to enable implicitly) could help.

@jorsn
Copy link
Member

jorsn commented Jan 8, 2024

Here is some tooling proposed in the other issue: #4945 (comment).
The idea is, you have a flake.template.nix written in ordinary Nix, which is used to generate the actual flake.nix.
With this, you can write your flake in normal Nix. When it is really worth it (!), then also the small overhead is justified.

The generation of flake.nix could even be wrapped as a flake app. One could make a flake template (that can be used by nix flake init – not the flake.template.nix) that provides a seed flake.nix only containing the generation app.

@jorsn
Copy link
Member

jorsn commented Jan 12, 2024

The generation of flake.nix could even be wrapped as a flake app. One could make a flake template (that can be used by nix flake init – not the flake.template.nix) that provides a seed flake.nix only containing the generation app.

Implemented: https://github.com/jorsn/flakegen.

@edolstra edolstra modified the milestones: nix-2.20, nix-2.21 Mar 4, 2024
@edolstra edolstra modified the milestones: nix-2.21, nix-2.22 Mar 11, 2024
znd4 pushed a commit to znd4/nixfiles that referenced this issue Mar 11, 2024
@edolstra edolstra modified the milestones: nix-2.22, nix-2.23 Apr 23, 2024
@edolstra edolstra removed this from the nix-2.23 milestone Jun 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
error-messages Confusing messages and better diagnostics flakes
Projects
None yet
Development

No branches or pull requests