Skip to content

mkLogosModule: a dependency with no matching flake input is silently dropped, then fails as a missing header #192

Description

@xAlisher

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions