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 eachView on GitHub (pinned to 1b2de5e052)
Solutions
- Ensure the referenced variable holds a str, int, or list before referencing it in list position.
- Stringify or remove the offending item (the message names its class and index).
- 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
- Ensure list-context <() expansions reference str/int/list variables only.
- Coerce bool/None config values to strings before binding them to list variables.
- Audit heterogeneous lists produced by templating layers.
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
- Variable %s must expand to a string or list of strings; list
- Variable %s must expand to a string or list of strings; foun
- Variable expansion in this context permits str and int only,
- Unknown type {item.__class__.__name__} at index {index}
- expected string list; got %r
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/265fea5c70f47b85.
Report an issue: GitHub.