nodejs/node · error · GypError

rule_sources must not exist in input, target %s rule %s

Error message

rule_sources must not exist in input, target %s rule %s

What it means

GYP itself synthesizes 'rule_sources' for each rule by scanning the target's sources for files matching the rule's extension. Hand-written 'rule_sources' in the input would be overwritten and is therefore rejected outright so authors do not rely on a value gyp will replace.

Source

Thrown at tools/gyp/pylib/gyp/input.py:2750

        if rule_extension in rule_extensions:
            raise GypError(
                (
                    "extension %s associated with multiple rules, "
                    + "target %s rules %s and %s"
                )
                % (
                    rule_extension,
                    target,
                    rule_extensions[rule_extension]["rule_name"],
                    rule_name,
                )
            )
        rule_extensions[rule_extension] = rule

        # Make sure rule_sources isn't already there.  It's going to be
        # created below if needed.
        if "rule_sources" in rule:
            raise GypError(
                "rule_sources must not exist in input, target %s rule %s"
                % (target, rule_name)
            )

        rule_sources = []
        source_keys = ["sources"]
        source_keys.extend(extra_sources_for_rules)
        for source_key in source_keys:
            for source in target_dict.get(source_key, []):
                (_source_root, source_extension) = os.path.splitext(source)
                if source_extension.startswith("."):
                    source_extension = source_extension[1:]
                if source_extension == rule_extension:
                    rule_sources.append(source)

        if len(rule_sources) > 0:
            rule["rule_sources"] = rule_sources

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Remove the 'rule_sources' key from the offending rule in the .gyp/.gypi file.
  2. If you need to control which sources a rule processes, instead curate the target's 'sources' list or the rule's extension; gyp derives rule_sources from those.
  3. Re-run gyp to confirm the rule now validates.

Example fix

// before
{ 'rule_name': 'gen', 'extension': 'idl', 'rule_sources': ['a.idl'], ... },
// after
{ 'rule_name': 'gen', 'extension': 'idl', ... },
Defensive patterns

Strategy: validation

Validate before calling

for r in target_dict.get('rules', []):
    if 'rule_sources' in r:
        raise ValueError(f"rule {r.get('rule_name')} must not preset 'rule_sources'")

Type guard

def rules_have_no_rule_sources(target_dict: dict) -> bool:
    return all('rule_sources' not in r for r in target_dict.get('rules', []))

Prevention

When it happens

Trigger: A rule dict inside a target's 'rules' list already contains a 'rule_sources' key before validation runs.

Common situations: Migrating from an older gyp layout that exposed rule_sources; manually editing a rule block generated by a tool and leaving the generated key in place; misunderstanding that rule_sources is an output, not an input.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/ae5ddb378be8ae9b. Report an issue: GitHub.