{"record":{"id":"e173620d3f8cf57b","repo":"nodejs/node","slug":"appending-s-to-a-non-list-setting-s-for-tool","errorCode":null,"errorMessage":"Appending \"%s\" to a non-list setting \"%s\" for tool \"%s\" is not allowed, previous value: %s","messagePattern":"Appending \"(.+?)\" to a non-list setting \"(.+?)\" for tool \"(.+?)\" is not allowed, previous value: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/generator/msvs.py","lineNumber":293,"sourceCode":"def _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset=False):\n    # TODO(bradnelson): ugly hack, fix this more generally!!!\n    if \"Directories\" in setting or \"Dependencies\" in setting:\n        if isinstance(value, str):\n            value = value.replace(\"/\", \"\\\\\")\n        else:\n            value = [i.replace(\"/\", \"\\\\\") for i in value]\n    if not tools.get(tool_name):\n        tools[tool_name] = {}\n    tool = tools[tool_name]\n    if setting == \"CompileAsWinRT\":\n        return\n    if tool.get(setting):\n        if only_if_unset:\n            return\n        if isinstance(tool[setting], list) and isinstance(value, list):\n            tool[setting] += value\n        else:\n            raise TypeError(\n                'Appending \"%s\" to a non-list setting \"%s\" for tool \"%s\" is '\n                \"not allowed, previous value: %s\"\n                % (value, setting, tool_name, str(tool[setting]))\n            )\n    else:\n        tool[setting] = value\n\n\ndef _ConfigTargetVersion(config_data):\n    return config_data.get(\"msvs_target_version\", \"Windows7\")\n\n\ndef _ConfigPlatform(config_data):\n    return config_data.get(\"msvs_configuration_platform\", \"Win32\")\n\n\ndef _ConfigBaseName(config_name, platform_name):\n    if config_name.endswith(\"_\" + platform_name):","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/generator/msvs.py#L275-L311","documentation":"Raised as a TypeError by the MSVS tool-setting merge helper when an 'append' operation would combine an existing setting value and a new value where at least one is not a list. The merge only auto-concatenates when both the stored value and the incoming value are lists; any scalar-vs-list mismatch is rejected to avoid silent data corruption of project settings.","triggerScenarios":"During MSVS project generation, merging tool settings where a setting already has a scalar (string) value and a list value is appended, or vice versa. Triggered inside the helper that processes msvs_settings/tool settings at msvs.py:289 when `isinstance(tool[setting], list) and isinstance(value, list)` is False but tool[setting] is already set and only_if_unset is False.","commonSituations":"A .gyp target sets an MSVS tool setting as a string in one place and another rule/condition appends a list to the same setting; mixing 'msvs_settings' overrides where one defines a scalar and another appends; conditional settings that change a field's effective type across configurations.","solutions":["Make the setting a list in both the original definition and the appended value so both are lists.","Audit the target's msvs_settings and any included .gypi for the offending setting name (shown in the message) and unify its value type.","If a scalar is intended, replace the append with a direct set (only_if_unset path) instead of an append."],"exampleFix":"// before — one place scalar, another appends a list\n'msvs_settings': { 'VCLinkerTool': { 'AdditionalDependencies': 'foo.lib' } }\n// ...later append of ['bar.lib'] fails\n// after — use a list consistently\n'msvs_settings': { 'VCLinkerTool': { 'AdditionalDependencies': ['foo.lib'] } }","handlingStrategy":"validation","validationCode":"def safe_append(existing, new):\n    if existing is None:\n        return new\n    if isinstance(existing, list) and isinstance(new, list):\n        return existing + new\n    raise TypeError(f'cannot append {type(new)} to {type(existing)}')","typeGuard":"def both_lists(a, b) -> bool:\n    return isinstance(a, list) and isinstance(b, list)","tryCatchPattern":"try:\n    _MergeToolSetting(tools, tool_name, setting, value, only_if_unset)\nexcept TypeError as e:\n    if 'non-list setting' in str(e):\n        coerce_setting_to_list(tools, tool_name, setting)\n    raise","preventionTips":["Keep a given MSVS tool setting consistently typed as a list across all overrides.","Review included .gypi files for conflicting scalar/list settings on the same key."],"tags":["gyp","msvs","tool-settings","type-mismatch","windows"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}