nodejs/node · error · ValueError

Variable expansion in this context permits strings and lists

Error message

Variable expansion in this context permits strings and lists only, found {expanded.__class__.__name__} at {index}

What it means

In ProcessVariablesAndConditionsInList, each list item that is a str is expanded via ExpandVariables. The expansion result must be a str, an int (assigned in place), or a list (spliced in place); any other type raises this ValueError naming the class and the list index. Note the message text says 'strings and lists only' but the code actually accepts int too — the error fires only for genuinely unsupported types like dict, bool, float, None.

Source

Thrown at tools/gyp/pylib/gyp/input.py:1424

        if isinstance(item, dict):
            # Make a copy of the variables dict so that it won't influence anything
            # outside of its own scope.
            ProcessVariablesAndConditionsInDict(item, phase, variables, build_file)
        elif isinstance(item, list):
            ProcessVariablesAndConditionsInList(item, phase, variables, build_file)
        elif isinstance(item, str):
            expanded = ExpandVariables(item, phase, variables, build_file)
            if type(expanded) in (str, int):
                the_list[index] = expanded
            elif isinstance(expanded, list):
                the_list[index : index + 1] = expanded
                index += len(expanded)

                # index now identifies the next item to examine.  Continue right now
                # without falling into the index increment below.
                continue
            else:
                raise ValueError(
                    "Variable expansion in this context permits strings and "
                    + "lists only, found "
                    + expanded.__class__.__name__
                    + " at "
                    + index
                )
        elif not isinstance(item, int):
            raise TypeError(
                "Unknown type " + item.__class__.__name__ + " at index " + index
            )
        index = index + 1


def BuildTargetsDict(data):
    """Builds a dict mapping fully-qualified target names to their target dicts.

    |data| is a dict mapping loaded build files by pathname relative to the
    current directory.  Values in |data| are build file contents.  For each

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Ensure the referenced variable holds a str, int, or list before referencing it in list position.
  2. Stringify or remove the offending item (the message names its class and index).
  3. If a bool/None leaked from config, coerce it to a string or 1/0 at the source.

Example fix

// before — flag_var holds a bool
'sources': ['a.c', '<(flag_var)', 'b.c'],
// after — make flag_var a string
'sources': ['a.c', '<(flag_var_str)', 'b.c'],
Defensive patterns

Strategy: type-guard

Validate before calling

for index, item in enumerate(the_list):
    if isinstance(item, str):
        expanded = ExpandVariables(item, phase, variables, build_file)
        assert type(expanded) in (str, int, list), \
            f'Item at index {index} expanded to unsupported {type(expanded).__name__}'

Type guard

def is_expandable_list_item(expanded) -> bool:
    return type(expanded) in (str, int) or isinstance(expanded, list)

Prevention

When it happens

Trigger: A list item is a '<(var)' reference whose value is a dict, bool, or None; a programmatic caller injects a heterogeneous list; expansion of a command yielding something other than text that decodes to a scalar/list.

Common situations: A list-valued variable that accidentally contains a dict; using '<(var)' where var holds a bool/None; templating layers injecting non-string scalars.

Related errors


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