nodejs/node · error · GypError
Found {dependency} in {dependency_key} of {target}, but not
Error message
Found {dependency} in {dependency_key} of {target}, but not in dependencies What it means
QualifyDependencies rewrites every dependency reference in sections derived from dependency_sections (dependencies, dependencies!, dependencies/) to its fully-qualified form. As a consistency rule, any dependency that appears in a non-primary section (dependencies! or dependencies/) must also appear in the plain 'dependencies' list of the same target. If it does not, GYP raises this GypError naming the dependency, the section it was found in, and the target. This enforces that hard deps and public-export deps are a subset of the build-time deps.
Source
Thrown at tools/gyp/pylib/gyp/input.py:1502
for index, dep in enumerate(dependencies):
dep_file, dep_target, dep_toolset = gyp.common.ResolveTarget(
target_build_file, dep, toolset
)
if not multiple_toolsets:
# Ignore toolset specification in the dependency if it is specified.
dep_toolset = toolset
dependency = gyp.common.QualifiedTarget(
dep_file, dep_target, dep_toolset
)
dependencies[index] = dependency
# Make sure anything appearing in a list other than "dependencies" also
# appears in the "dependencies" list.
if (
dependency_key != "dependencies"
and dependency not in target_dict["dependencies"]
):
raise GypError(
"Found "
+ dependency
+ " in "
+ dependency_key
+ " of "
+ target
+ ", but not in dependencies"
)
def ExpandWildcardDependencies(targets, data):
"""Expands dependencies specified as build_file:*.
For each target in |targets|, examines sections containing links to other
targets. If any such section contains a link of the form build_file:*, it
is taken as a wildcard link, and is expanded to list each target in
build_file. The |data| dict provides access to build file dicts.
View on GitHub (pinned to 1b2de5e052)
Solutions
- Add the named dependency to the target's plain 'dependencies' list as well.
- Re-audit dependencies! and dependencies/ to confirm each entry is also in dependencies.
- If the dep was removed intentionally, remove it from all three sections consistently.
Example fix
// before 'dependencies': ['base'], 'dependencies!': ['codegen'], // codegen not in dependencies // after 'dependencies': ['base', 'codegen'], 'dependencies!': ['codegen'],
Defensive patterns
Strategy: validation
Validate before calling
for section in ('dependencies!', 'dependencies/'):
for dep in target_dict.get(section, []):
assert dep in target_dict.get('dependencies', []), \
f'{dep} listed in {section} of {target} but missing from dependencies' Type guard
def aux_deps_are_subset_of_dependencies(target_dict) -> bool:
base = set(target_dict.get('dependencies', []))
return all(set(target_dict.get(s, [])) <= base
for s in ('dependencies!', 'dependencies/')) Prevention
- Whenever you add a dep to dependencies! or dependencies/, also add it to dependencies.
- Keep the three dependency sections in sync during refactors.
- Lint target dicts for the subset relationship before committing.
When it happens
Trigger: A target lists a dep in 'dependencies!' (hard dependencies) or 'dependencies/' (dependents exported for include paths) but omits it from 'dependencies'; renaming a dep in one list but not the other; a refactor that moved a dep into dependencies! assuming it would be implicitly added to dependencies.
Common situations: Adding a header-only or link-time dep to 'dependencies!' and forgetting to mirror it in 'dependencies'; merging conditions that inject a dep into one list only; tooling that edits one section independently.
Related errors
- | cannot handle absolute paths, got "%s"
- Error importing pymod_do_mainmodule (%s): %s
- Unknown command string '%s' in '%s'.
- %s while executing command '%s' in %s
- Call to '%s' returned exit status %d while in %s.
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/c58a6d5ea32cdec3.
Report an issue: GitHub.