Nix 2.17 stops losing nested dynamic attributes
A parser fix in Nix 2.17 preserves dynamic attributes when repeated nested declarations merge. The release also separates permission to sign store paths from the broader trusted-user role.
Silently dropping a configuration value is a particularly damaging parser failure in a declarative system. A build can proceed with a valid-looking result while omitting part of the declared intent. Nix 2.17 repairs one such case involving repeated nested attribute-set declarations and a dynamically computed attribute name.
The release notes, dated July 24, explain the missing value with a small example. Their historical version at the release tag states the same bug and also questions the readability of relying on repeated declarations in the first place. This fix preserves the existing language behavior while acknowledging the source form's problems.
I value Nix because a configuration describes what should exist. Losing a declared field during parsing undermines that relationship before package building or system activation begins. This repair matters even when the unusual source form is one that authors should generally avoid.
A computed name disappeared during merging
The release's example declares nested twice. The first declaration contains a literal attribute, and the second contains an attribute whose name comes from an expression:
{
nested = { foo = 1; };
nested = { ${"ba" + "r"} = 2; };
}
Previously, the parser silently discarded nested.bar. Nix 2.17 preserves it and evaluates the expression to a set whose nested value contains both foo = 1 and bar = 2. The dynamic expression produces the name bar, so the second declaration has a concrete intended contribution.
This is not a request to overwrite foo with a second value. The two nested declarations contain different attributes. The problematic behavior occurs while combining those declarations, where the computed-name contribution was lost. Describing it as an ordinary last-value-wins rule would misstate the release's example.
The language reference at this version describes attribute sets as collections of name/value pairs. Values can be arbitrary expressions, and ordinary attribute names must be unique within their set. That general description makes the special historical behavior around repeated nested declarations worth calling out explicitly.
Compatibility and readability have separate answers
The release notes do not celebrate repeated attribute-set declarations as a preferred style. They say the behavior has existed for a long time and remains for compatibility. They also point out that declarations separated by many lines can make code difficult to read.
Those statements are compatible with fixing the parser. Existing accepted source needs the documented result, including its dynamic names. A maintainer should not have to accept silent data loss merely because another source form would be easier to review.
At the same time, a parser correction does not eliminate the source form's readability cost. To understand the final nested set, a reader must find each contribution and know the merge behavior. Computed names add another step because the reader must evaluate the naming expression too.
The useful distinction is between supporting an existing contract and recommending it for new code. Nix 2.17 does the former here. The release's caution about relying on repeated declarations belongs to source design, while the fix belongs to correctness of existing programs.
I find that a reasonable maintenance position. Declarative configuration benefits from clear definitions, but language implementations still owe existing expressions consistent results. Readability guidance should not be used to excuse a parser silently removing part of an accepted expression.
The failure happens before realization
The release identifies this as a parser fix. It therefore affects the expression that later evaluation sees, before a derivation can describe build inputs. A successful downstream build cannot establish that the parser preserved the original declaration correctly.
This limits what a package-level success tells an operator. A package can build under the resulting configuration even if that configuration lacks a value the author intended. Inspecting the evaluated attributes is the relevant observation for the release's minimal example.
The corrected result supplies a direct behavioral criterion. Both nested attributes must be present with their stated values. An evaluation that retains only foo still exhibits the reported failure. The release does not need a performance benchmark to establish the repair because the old and new outputs differ in a concrete field.
It also does not claim to redesign every form of merging in NixOS. The module system and its option-merging behavior are a separate layer from this parser example. Conflating them would make the defect sound broader than the documented case and obscure where the repair applies.
Signing no longer requires the broader trusted role
Nix 2.17 also lets unprivileged allowed users sign store paths. Previously that operation required a trusted user. The release notes state the permission change separately from the parser fix, but it is another case where a narrow operation receives a more specific contract.
The signing command implementation still requires a secret key file. It reads that key, obtains path information, computes a signature, and adds the signature when it is not already present. Allowing a user to invoke the operation does not give that user somebody else's signing key.
This separates local permission to attach a signature from possession of the private material needed to produce it. A verifier's trust in a signing identity is another consideration again. The release's change is not a declaration that every signature produced by an allowed user should automatically be trusted by all consumers.
That matters for automation arranged around a dedicated signing identity. The caller can perform the signing operation without acquiring the broader trusted-user role solely for that purpose. The command still expresses the key requirement directly, and the store receives the resulting signature for the named path.
Nix 2.17's parser correction preserves a declared value that previously disappeared. Its signing permission change narrows a separate administrative requirement. Both changes become understandable when their layer is explicit, with expression parsing determining configuration data and signing determining an artifact's attached authentication metadata.