A dependencies entry in metadata.json that has no prebuilt SDK header and no exactly-matching flake input is silently dropped. The build then fails much later with a missing-header compile error that gives no hint the flake input was the problem.
Two sibling code paths in the same file already throw clear errors for this exact class of mistake. The most common path — plain dependencies — does not.
Where
lib/mkLogosModule.nix:160
moduleInputs = lib.filterAttrs (n: _: builtins.elem n legacyHeaderDepNames) flakeInputs;
filterAttrs matches the flake input's attribute name against the dependency string. A name that doesn't match is discarded with no diagnostic. There is no subsequent check that every legacyHeaderDepName actually resolved.
Reproduce
metadata.json:
{ "name": "node_remote", "type": "core", "interface": "universal",
"dependencies": ["blockchain_module"] }
flake.nix — note the hyphen, which is the natural spelling for a Nix attribute and matches the repo name:
inputs = {
logos-module-builder.url = "github:logos-co/logos-module-builder";
blockchain-module.url = "github:logos-blockchain/logos-blockchain-module/0.2.1";
};
nix build .#packages.x86_64-linux.default:
> /build/node_remote/generated_code/include/logos_sdk.h:3:10: fatal error: blockchain_module_api.h: No such file or directory
Rename the input to blockchain_module (underscore, exactly matching the dependency string) and the same build succeeds. Nothing else changes.
Why this is easy to hit
- Nix attribute names conventionally use hyphens, and the repo is called
logos-blockchain-module, so blockchain-module is the natural thing to write. The module name is blockchain_module. The two differ by one character.
- The error names
blockchain_module_api.h and logos_sdk.h — both generated files. Nothing in the message mentions flake inputs, so the obvious reading is "this dependency doesn't ship a header", which sends you looking for a vendoring workaround rather than at your input name.
- The requirement that the input attribute name equal the dependency string is not stated in the README or in the template's comments. It is only discoverable by reading
mkLogosModule.nix.
I lost roughly two hours to this and concluded the flake-input route was broken for non-platform deps, which is wrong — it works correctly once the name matches.
The asymmetry
The same file already produces good errors for the two adjacent cases:
mkLogosModule.nix:139
else throw "dependency_overrides.${name}: flake input '${ov.input}' was not passed to mkLogosModule."
mkLogosModule.nix:199
else throw "interface_dependencies: interface '${e.name}' references flake input '${e.input}', but no such input was passed to mkLogosModule (declare it in flake.nix and pass it via flakeInputs)."
Plain dependencies is the path most module authors use, and it is the one path with no check.
Suggested fix
After computing moduleInputs, assert that every legacy-header dep resolved to either a prebuilt SDK header or a flake input, and name the near-miss when there is one:
unresolvedDeps = lib.filter (n: !(moduleInputs ? ${n}) && !(sdkProvides n)) legacyHeaderDepNames;
_ = lib.throwIf (unresolvedDeps != []) ''
mkLogosModule: dependency ${lib.head unresolvedDeps} could not be resolved.
It ships no prebuilt SDK header, so it must come from a flake input whose
ATTRIBUTE NAME equals the dependency string exactly.
Declared inputs: ${lib.concatStringsSep ", " (lib.attrNames flakeInputs)}
Did you mean to rename an input to `${lib.head unresolvedDeps}`?
'';
Even without the did-you-mean, listing the declared input names next to the expected one would make this a ten-second fix instead of a two-hour one.
A one-line README note would also help: "a dependency resolved from a flake input requires the input's attribute name to match the dependency string exactly — blockchain_module, not blockchain-module."
Environment
logos-module-builder @ /nix/store/nwv11daf2m1bk2fkxa5k0x5r9v0xs7a4-…-source (built 2026-08-11)
- Consumer: a
type: core, interface: universal module
- Dependency:
logos-blockchain/logos-blockchain-module @ tag 0.2.1
Unrelated second bug, same afternoon
The scaffold template (nix flake init -t github:logos-co/logos-module-builder) generates:
string(JSON MODULE_NAME GET ${METADATA_JSON} name)
${METADATA_JSON} unquoted is expanded by CMake as a list, corrupting the JSON before string(JSON …) parses it. It fails as:
CMake Error: string sub-command JSON failed parsing json string: * Line 11, Column 21
Syntax error: value, object or array expected.
CMake Error at cmake/LogosModule.cmake:216 (message):
logos_module: NAME is required
The reported error is NAME is required, which points at the logos_module() call rather than the parse. It stays dormant until metadata.json contains something CMake treats as a list separator, so a module can build for weeks and then break on an unrelated metadata edit. Fix is to quote it:
string(JSON MODULE_NAME GET "${METADATA_JSON}" name)
Happy to send a PR for either or both.
A
dependenciesentry inmetadata.jsonthat has no prebuilt SDK header and no exactly-matching flake input is silently dropped. The build then fails much later with a missing-header compile error that gives no hint the flake input was the problem.Two sibling code paths in the same file already throw clear errors for this exact class of mistake. The most common path — plain
dependencies— does not.Where
lib/mkLogosModule.nix:160filterAttrsmatches the flake input's attribute name against the dependency string. A name that doesn't match is discarded with no diagnostic. There is no subsequent check that everylegacyHeaderDepNameactually resolved.Reproduce
metadata.json:{ "name": "node_remote", "type": "core", "interface": "universal", "dependencies": ["blockchain_module"] }flake.nix— note the hyphen, which is the natural spelling for a Nix attribute and matches the repo name:nix build .#packages.x86_64-linux.default:Rename the input to
blockchain_module(underscore, exactly matching the dependency string) and the same build succeeds. Nothing else changes.Why this is easy to hit
logos-blockchain-module, soblockchain-moduleis the natural thing to write. The module name isblockchain_module. The two differ by one character.blockchain_module_api.handlogos_sdk.h— both generated files. Nothing in the message mentions flake inputs, so the obvious reading is "this dependency doesn't ship a header", which sends you looking for a vendoring workaround rather than at your input name.mkLogosModule.nix.I lost roughly two hours to this and concluded the flake-input route was broken for non-platform deps, which is wrong — it works correctly once the name matches.
The asymmetry
The same file already produces good errors for the two adjacent cases:
mkLogosModule.nix:139mkLogosModule.nix:199Plain
dependenciesis the path most module authors use, and it is the one path with no check.Suggested fix
After computing
moduleInputs, assert that every legacy-header dep resolved to either a prebuilt SDK header or a flake input, and name the near-miss when there is one:Even without the did-you-mean, listing the declared input names next to the expected one would make this a ten-second fix instead of a two-hour one.
A one-line README note would also help: "a dependency resolved from a flake input requires the input's attribute name to match the dependency string exactly —
blockchain_module, notblockchain-module."Environment
logos-module-builder@/nix/store/nwv11daf2m1bk2fkxa5k0x5r9v0xs7a4-…-source(built 2026-08-11)type: core,interface: universalmodulelogos-blockchain/logos-blockchain-module@ tag0.2.1Unrelated second bug, same afternoon
The scaffold template (
nix flake init -t github:logos-co/logos-module-builder) generates:${METADATA_JSON}unquoted is expanded by CMake as a list, corrupting the JSON beforestring(JSON …)parses it. It fails as:The reported error is
NAME is required, which points at thelogos_module()call rather than the parse. It stays dormant untilmetadata.jsoncontains something CMake treats as a list separator, so a module can build for weeks and then break on an unrelated metadata edit. Fix is to quote it:Happy to send a PR for either or both.