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
- Open the target named in the message, list every entry under 'rules', and locate the two with identical 'rule_name'.
- Rename one of the duplicate rule_name values to a unique identifier that describes what that rule does.
- 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
- Adopt a naming convention for rule_name (verb + object, e.g. 'compile_protos').
- Run a quick local gyp invocation after each rule edit to catch collisions early.
- In code review, watch for copy-pasted rule blocks.
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
- extension %s associated with multiple rules, target %s rules
- rule_sources must not exist in input, target %s rule %s
- Duplicate targets in isolate map files: %s.
- AddFileConfig: file "%s" not in project.
- expected string; got %r
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/6fc5522c10f32603.
Report an issue: GitHub.