{"record":{"id":"5d8c4b458ce814c1","repo":"nodejs/node","slug":"attempt-to-merge-dict-value-of-type-v-class-5d8c4b","errorCode":null,"errorMessage":"Attempt to merge dict value of type {v.__class__.__name__} into incompatible type {to[list_base].__class__.__name__} for key {list_base}({k})","messagePattern":"Attempt to merge dict value of type (.+?) into incompatible type (.+?) for key (.+?)\\((.+?)\\)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/input.py","lineNumber":2356,"sourceCode":"\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\n                        + \"(\"\n                        + k\n                        + \")\"\n                    )\n            else:\n                to[list_base] = []\n\n            # Call MergeLists, which will make copies of objects that require it.\n            # MergeLists can recurse back into MergeDicts, although this will be\n            # to make copies of dicts (with paths fixed), there will be no\n            # subsequent dict \"merging\" once entering a list because lists are\n            # always replaced, appended to, or prepended to.","sourceCodeStart":2338,"sourceCodeEnd":2374,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/input.py#L2338-L2374","documentation":"A companion to error 509 for list-suffixed keys: when merging a suffixed list key (e.g. 'sources+') into destination 'to', the base key (e.g. 'sources') must already be a list if present. If to[list_base] exists but is not a list (e.g. it is a string), MergeDicts raises TypeError naming the value type, the existing type, and both the base and suffixed key.","triggerScenarios":"The destination dict 'to' has list_base set to a non-list value, and a merge introduces a suffixed variant (k = list_base + '=' / '?' / '+'). Reached after the incompatible-policy check passes.","commonSituations":"Target defines 'sources' as a string (mistake) while an include merges 'sources+'; configuration inheritance turning a list into a scalar; earlier merge corruption.","solutions":["Ensure to[list_base] is a list whenever you also use a suffixed variant of that key.","Convert the scalar to a single-element list, or remove the conflicting entry.","Audit the order of merges that populate 'to'."],"exampleFix":"// before: { 'sources': 'a.cc' } merged with { 'sources+': ['b.cc'] }\n// after: { 'sources': ['a.cc'] } merged with { 'sources+': ['b.cc'] }","handlingStrategy":"type-guard","validationCode":"for k in list(the_dict):\n    if k[-1:] in ('=','?','+'):\n        base = k[:-1]\n        if base in the_dict and not isinstance(the_dict[base], list):\n            raise TypeError('%s must be a list to use %s' % (base, k))\n","typeGuard":"def base_is_list(d, suffixed_key): return isinstance(d.get(suffixed_key[:-1]), list)","tryCatchPattern":"try:\n    MergeDicts(to, fro, to_file, fro_file)\nexcept TypeError as e:\n    if 'incompatible type' in str(e) and '(' in str(e): print('Make the base list key an actual list'); raise","preventionTips":["Keep list bases as lists whenever you use suffix variants.","Don't overwrite a list base with a scalar via includes.","Lint for scalar list bases."],"tags":["gyp","merge","type-error","list-policy","validation"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}