本资料汇总 Nix 生态中“看起来成功、实则什么都没验证”的失败模式,假定读者已掌握基础语法,只覆盖容易出错的点。
用途:帮助编写 Nix 表达式、flake.nix、home-manager 配置、programs./services. 模块、nixpkgs 打包,以及执行 nix flake check 时避开静默错误。
主要能力与要点: 一、Flakes。flake 构建解析的是 git 树而非工作树:nix build .#pkg、nix flake check、nix eval .#x 都通过 git 树获取器解析 self,未跟踪文件在树中不存在,即使磁盘上存在;路径式求值(nix-instantiate --eval、import ./x、nix build -f default.nix)读取原始文件系统。可用 git status --porcelain -- <path> 判断,?? 表示未跟踪且对 flake 不可见。nix flake check 在 flake 未列出的平台上可能没有任何可检查项,退出码 0 却什么都没验证;可在受支持系统上原生运行,或强制完整求值:nix flake check --all-systems --no-write-lock-file --print-build-logs --keep-going。依赖其他 flake 的包时优先使用其 overlays.default,因为 packages 输出按系统键控,仅在对方列出的系统上存在,否则报属性缺失。锁版本应枚举标签(git ls-remote --tags <url> 或 forge 的 tags 端点),不要用 latest release 端点,后者会静默锁到更旧版本。用 inputs.nixpkgs.follows 保持单一依赖图,避免 flake.lock 中出现多个 nixpkgs 节点导致核心库分叉、缓存未命中与 ABI 不匹配;个别例外应隔离为单节点并注明原因。
二、模块。programs.* 与 services.* 在 NixOS 与 Home Manager 中同名但模式不同,解析到哪个命名空间由求值该文件的模块系统决定,而非文件本身;若已知支持的选项被报不存在,先沿导入链确认是 nixosSystem/nixosModules 还是 homeManagerConfiguration/home-manager.users.<name>。home.file 用 source 或 text 声明会生成指向 Nix store 的只读符号链接,应用自身设置界面无法写回这些键,部分应用退出时重写整个配置文件会失败并丢失其他状态。freeformType 会接受未文档化的键而不校验,拼写错误会静默失效。builtins.readFile/fromJSON/import 作用于派生输出内的路径会触发导入派生(IFD),破坏跨平台模块;可用 --option allow-import-from-derivation false 让其显式报错。两个导入都设置 _module.args 会报属性重复定义。文件较多时用 builtins.readDir 自动发现,按类型过滤。通过 imports = [ ./x ] 引入的模块签名需含 ...。跨切常量用 specialArgs/extraSpecialArgs 或 _module.args 传递。Git 钩子分全局与项目两层,脚本中建议用 NUL 分隔迭代。
三、打包。版本应从语言清单派生(如 Cargo.toml、package.json、pyproject.toml),硬编码会静默漂移;按标签获取的外部发布则应保留字面版本。Rust 的 overrideAttrs 不能通过新 cargoHash 改变已 vendored 依赖;nixpkgs 25.05+ 默认使用 fetchCargoVendor,cargoHash 仍必需,未知哈希可先用 lib.fakeHash。Darwin 改用捆绑的版本化 SDK,未版本化的 darwin.apple_sdk.frameworks.* 应删除。JavaScript 按锁文件选择构建器(npm 用 buildNpmPackage、pnpm 用 stdenvNoCC.mkDerivation + fetchPnpmDeps + pnpmConfigHook、bun 两阶段)。带守护进程的 monorepo 工具(如 turbo)会破坏沙箱清理,需禁用守护进程与缓存并在 buildPhase 末尾清理。哈希统一用 SRI 格式。
限制:本资料为陷阱清单,未提供完整官方文档;具体价格、平台支持范围与最新版本行为暂未提供,应以实际 nixpkgs 与上游文档为准。