{"record":{"id":"f1bea76c9f6145c2","repo":"nodejs/node","slug":"incompatible-list-policies-k-and-list-incompati","errorCode":null,"errorMessage":"Incompatible list policies {k} and {list_incompatible}","messagePattern":"Incompatible list policies (.+?) and (.+?)","errorType":"exception","errorClass":"GypError","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/input.py","lineNumber":2344,"sourceCode":"                lists_incompatible = [list_base, list_base + \"?\"]\n                to[list_base] = []\n            elif ext == \"+\":\n                list_base = k[:-1]\n                lists_incompatible = [list_base + \"=\", list_base + \"?\"]\n                append = False\n            elif ext == \"?\":\n                list_base = k[:-1]\n                lists_incompatible = [list_base, list_base + \"=\", list_base + \"+\"]\n            else:\n                list_base = k\n                lists_incompatible = [list_base + \"=\", list_base + \"?\"]\n\n            # Some combinations of merge policies appearing together are meaningless.\n            # It's stupid to replace and append simultaneously, for example.  Append\n            # and prepend are the only policies that can coexist.\n            for list_incompatible in lists_incompatible:\n                if list_incompatible in fro:\n                    raise GypError(\n                        \"Incompatible list policies \" + k + \" and \" + list_incompatible\n                    )\n\n            if list_base in to:\n                if ext == \"?\":\n                    # If the key ends in \"?\", the list will only be merged if it doesn't\n                    # already exist.\n                    continue\n                elif not isinstance(to[list_base], list):\n                    # This may not have been checked above if merging in a list with an\n                    # extension character.\n                    raise TypeError(\n                        \"Attempt to merge dict value of type \"\n                        + v.__class__.__name__\n                        + \" into incompatible type \"\n                        + to[list_base].__class__.__name__\n                        + \" for key \"\n                        + list_base","sourceCodeStart":2326,"sourceCodeEnd":2362,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/input.py#L2326-L2362","documentation":"GYP list keys support merge-policy suffixes: base (append), 'base=' (replace), 'base?' (only-if-absent), 'base+' (prepend). Certain combinations are meaningless (replace+append, replace+prepend, etc.). When a suffixed key and an incompatible sibling are both present in the same 'fro' dict, gyp raises GypError listing both policies.","triggerScenarios":"Within one dict being merged, two of {list_base, list_base+'=', list_base+'?', list_base+'+'} that the code marks incompatible coexist. E.g. both 'sources' and 'sources=', or 'sources?' and 'sources+', etc.","commonSituations":"Copy-pasting sources lists with different suffixes; an include adding 'sources+' while the target already has 'sources='; refactoring that left stale suffixed keys; misunderstanding the suffix semantics.","solutions":["Keep at most one merge policy per list base within a single dict (append and prepend are the only pair that may coexist).","Remove the redundant/contradictory suffixed key.","If you need replace semantics, use only 'key=' and drop the bare 'key'."],"exampleFix":"// before: { 'sources': [...], 'sources=': [...] }\n// after: { 'sources=': [...] }  // replace only","handlingStrategy":"validation","validationCode":"import re\nbase_keys = {}\nfor k in the_dict:\n    m = re.match(r'^(.*?)([=?+/!]?)$', k)\n    base_keys.setdefault(m.group(1), set()).add(k)\nfor base, keys in base_keys.items():\n    if len(keys) > 1 and not keys <= {base, base+'+'}:\n        raise SystemExit('Incompatible list policies: %r' % keys)\n","typeGuard":null,"tryCatchPattern":"try:\n    gyp.main(args)\nexcept gyp.input.GypError as e:\n    if 'Incompatible list policies' in str(e): print('Remove one of the conflicting suffixed keys'); raise","preventionTips":["Use at most one merge policy per list base (append+prepend is the only allowed pair).","Avoid mixing bare key with '=' replace.","Document the suffix semantics for contributors."],"tags":["gyp","merge","list-policy","validation","build-config"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}