nodejs/node · error · GypError

rule {rule_name} exists in duplicate, target {target}

Error message

rule {rule_name} exists in duplicate, target {target}

What it means

GYP's ValidateRulesInTarget inspects every entry in a target's 'rules' list and requires each 'rule_name' key to be unique within that target. The loop accumulates names into a dict; on a second occurrence of the same name it raises GypError. This guarantees that later rule expansion and source-matching can address a single, unambiguous rule.

Source

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

    Arguments:
      target: string, name of target.
      target_dict: dict, target spec containing "rules" and "sources" lists.
      extra_sources_for_rules: a list of keys to scan for rule matches in
          addition to 'sources'.
    """

    # Dicts to map between values found in rules' 'rule_name' and 'extension'
    # keys and the rule dicts themselves.
    rule_names = {}
    rule_extensions = {}

    rules = target_dict.get("rules", [])
    for rule in rules:
        # Make sure that there's no conflict among rule names and extensions.
        rule_name = rule["rule_name"]
        if rule_name in rule_names:
            raise GypError(f"rule {rule_name} exists in duplicate, target {target}")
        rule_names[rule_name] = rule

        rule_extension = rule["extension"]
        if rule_extension.startswith("."):
            rule_extension = rule_extension[1:]
        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,
                )
            )

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Open the target named in the message, list every entry under 'rules', and locate the two with identical 'rule_name'.
  2. Rename one of the duplicate rule_name values to a unique identifier that describes what that rule does.
  3. Re-run gyp and confirm the message no longer appears for that target.

Example fix

// before
'rules': [
  { 'rule_name': 'gen_proto', 'extension': 'proto', ... },
  { 'rule_name': 'gen_proto', 'extension': 'proto', ... },
],
// after
'rules': [
  { 'rule_name': 'gen_proto', 'extension': 'proto', ... },
  { 'rule_name': 'gen_grpc', 'extension': 'grpc', ... },
],
Defensive patterns

Strategy: validation

Validate before calling

# Before authoring a target, lint its rules for unique names.
rules = target_dict.get('rules', [])
seen = set()
for r in rules:
    name = r.get('rule_name')
    if name in seen:
        raise ValueError(f'duplicate rule_name {name!r} in target')
    seen.add(name)

Type guard

def has_unique_rule_names(target_dict: dict) -> bool:
    names = [r.get('rule_name') for r in target_dict.get('rules', [])]
    return len(names) == len(set(names))

Prevention

When it happens

Trigger: A .gyp(i) target dict contains two entries in its 'rules' array whose 'rule_name' fields hold the same string value (exact match, case-sensitive).

Common situations: Copy-pasting a rule block when adding a new build rule and forgetting to rename rule_name; merging two .gypi includes that both contribute a rule with the same name into one target; refactoring a rule and leaving the old entry behind.

Related errors


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