{"record":{"id":"6fc5522c10f32603","repo":"nodejs/node","slug":"rule-rule-name-exists-in-duplicate-target-targ","errorCode":null,"errorMessage":"rule {rule_name} exists in duplicate, target {target}","messagePattern":"rule (.+?) exists in duplicate, target (.+?)","errorType":"exception","errorClass":"GypError","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/input.py","lineNumber":2726,"sourceCode":"\n    Arguments:\n      target: string, name of target.\n      target_dict: dict, target spec containing \"rules\" and \"sources\" lists.\n      extra_sources_for_rules: a list of keys to scan for rule matches in\n          addition to 'sources'.\n    \"\"\"\n\n    # Dicts to map between values found in rules' 'rule_name' and 'extension'\n    # keys and the rule dicts themselves.\n    rule_names = {}\n    rule_extensions = {}\n\n    rules = target_dict.get(\"rules\", [])\n    for rule in rules:\n        # Make sure that there's no conflict among rule names and extensions.\n        rule_name = rule[\"rule_name\"]\n        if rule_name in rule_names:\n            raise GypError(f\"rule {rule_name} exists in duplicate, target {target}\")\n        rule_names[rule_name] = rule\n\n        rule_extension = rule[\"extension\"]\n        if rule_extension.startswith(\".\"):\n            rule_extension = rule_extension[1:]\n        if rule_extension in rule_extensions:\n            raise GypError(\n                (\n                    \"extension %s associated with multiple rules, \"\n                    + \"target %s rules %s and %s\"\n                )\n                % (\n                    rule_extension,\n                    target,\n                    rule_extensions[rule_extension][\"rule_name\"],\n                    rule_name,\n                )\n            )","sourceCodeStart":2708,"sourceCodeEnd":2744,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/input.py#L2708-L2744","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\n'rules': [\n  { 'rule_name': 'gen_proto', 'extension': 'proto', ... },\n  { 'rule_name': 'gen_proto', 'extension': 'proto', ... },\n],\n// after\n'rules': [\n  { 'rule_name': 'gen_proto', 'extension': 'proto', ... },\n  { 'rule_name': 'gen_grpc', 'extension': 'grpc', ... },\n],","handlingStrategy":"validation","validationCode":"# Before authoring a target, lint its rules for unique names.\nrules = target_dict.get('rules', [])\nseen = set()\nfor r in rules:\n    name = r.get('rule_name')\n    if name in seen:\n        raise ValueError(f'duplicate rule_name {name!r} in target')\n    seen.add(name)","typeGuard":"def has_unique_rule_names(target_dict: dict) -> bool:\n    names = [r.get('rule_name') for r in target_dict.get('rules', [])]\n    return len(names) == len(set(names))","tryCatchPattern":null,"preventionTips":["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."],"tags":["gyp","rules","duplicate","validation"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}