nodejs/node · error · ValueError

expected string list; got %r

Error message

expected string list; got %r

What it means

_StringList.ValidateMSVS raises ValueError('expected string list; got %r') when the value for an MSVS list-typed setting is neither a list nor a str. List settings (e.g. AdditionalIncludeDirectories, PreprocessorDefinitions) accept either a Python list of strings or a single string; anything else (int, dict, None, nested list) is rejected.

Source

Thrown at tools/gyp/pylib/gyp/MSVSSettings.py:126

    def ValidateMSVS(self, value):
        if not isinstance(value, str):
            raise ValueError("expected string; got %r" % value)

    def ValidateMSBuild(self, value):
        if not isinstance(value, str):
            raise ValueError("expected string; got %r" % value)

    def ConvertToMSBuild(self, value):
        # Convert the macros
        return ConvertVCMacrosToMSBuild(value)


class _StringList(_Type):
    """A settings that's a list of strings."""

    def ValidateMSVS(self, value):
        if not isinstance(value, (list, str)):
            raise ValueError("expected string list; got %r" % value)

    def ValidateMSBuild(self, value):
        if not isinstance(value, (list, str)):
            raise ValueError("expected string list; got %r" % value)

    def ConvertToMSBuild(self, value):
        # Convert the macros
        if isinstance(value, list):
            return [ConvertVCMacrosToMSBuild(i) for i in value]
        else:
            return ConvertVCMacrosToMSBuild(value)


class _Boolean(_Type):
    """Boolean settings, can have the values 'false' or 'true'."""

    def _Validate(self, value):
        if value not in {"true", "false"}:

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Wrap the value in a list: [value] if it is a single string, or ensure it is already a list.
  2. Omit the setting entirely when it would be None rather than passing None.
  3. Confirm the setting is registered as _StringList in MSVSSettings and supply the expected shape.

Example fix

# before
'AdditionalIncludeDirectories': INC_DIR,  # INC_DIR is int or None

# after
'AdditionalIncludeDirectories': [str(INC_DIR)] if INC_DIR else [],
Defensive patterns

Strategy: type-guard

Validate before calling

def coerce_string_list(value):
    if value is None:
        return []
    if isinstance(value, str):
        return [value]
    if isinstance(value, list):
        if not all(isinstance(i, str) for i in value):
            raise TypeError('list items must be str')
        return value
    raise TypeError('expected str or list of str, got %r' % type(value))

Type guard

def is_string_list(value) -> bool:
    return isinstance(value, str) or (isinstance(value, list) and all(isinstance(i, str) for i in value))

Try / catch

try:
    _file_list.ValidateMSVS(my_list)
except ValueError:
    my_list = coerce_string_list(my_list)
    _file_list.ValidateMSVS(my_list)

Prevention

When it happens

Trigger: Setting a list-type MSVS setting to an int/None/dict; passing a semicolon-separated string is fine, but passing a non-string scalar is not.

Common situations: Refactor that turned a list literal into a single computed value without wrapping it in [ ]; templating code that sometimes yields None for an optional include dir.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/8a2d7f3ef48099ba. Report an issue: GitHub.