nodejs/node · error · ValueError
{name} key {list_key} must be list, not {value.__class__.__n
Error message
{name} key {list_key} must be list, not {value.__class__.__name__} when applying {"!": "exclusion", "/": "regex"}[operation] What it means
When a list-filter key ('sources!'/sources/') is itself a list, the BASE list it operates on ('sources') must also be a list. If the_dict[list_key] is present but not a list, gyp raises ValueError naming the base key, its actual type, and the operation (exclusion or regex).
Source
Thrown at tools/gyp/pylib/gyp/input.py:2546
if operation not in {"!", "/"}:
continue
if not isinstance(value, list):
raise ValueError(
name + " key " + key + " must be list, not " + value.__class__.__name__
)
list_key = key[:-1]
if list_key not in the_dict:
# This happens when there's a list like "sources!" but no corresponding
# "sources" list. Since there's nothing for it to operate on, queue up
# the "sources!" list for deletion now.
del_lists.append(key)
continue
if not isinstance(the_dict[list_key], list):
value = the_dict[list_key]
raise ValueError(
name
+ " key "
+ list_key
+ " must be list, not "
+ value.__class__.__name__
+ " when applying "
+ {"!": "exclusion", "/": "regex"}[operation]
)
if list_key not in lists:
lists.append(list_key)
# Delete the lists that are known to be unneeded at this point.
for del_list in del_lists:
del the_dict[del_list]
for list_key in lists:
the_list = the_dict[list_key]View on GitHub (pinned to 1b2de5e052)
Solutions
- Ensure the base key (the part before '!' or '/') is a list whenever a filter for it exists.
- Convert the scalar to a single-element list or remove the filter.
- Check merge/include order that may have overwritten the base.
Example fix
// before: { 'sources': 'a.cc', 'sources!': ['a.cc'] }
// after: { 'sources': ['a.cc', 'b.cc'], 'sources!': ['a.cc'] } Defensive patterns
Strategy: type-guard
Validate before calling
for k, v in the_dict.items():
if k[-1:] in ('!', '/') and isinstance(v, list):
base = k[:-1]
if base in the_dict:
assert isinstance(the_dict[base], list), '%s base must be list' % base
Type guard
def base_is_list_when_filtered(d, filter_key): return isinstance(d.get(filter_key[:-1]), list)
Try / catch
try:
gyp.main(args)
except ValueError as e:
if 'must be list' in str(e) and 'when applying' in str(e): print('Make the base list a real list'); raise Prevention
- Ensure the base list is actually a list before adding '!'/ and '/' filters.
- Don't let merges convert a list base to a scalar.
- Lint list bases alongside their filters.
When it happens
Trigger: the_dict contains both a filter key (e.g. 'sources!') that is a valid list AND a base key 'sources' that is NOT a list (e.g. a string or None). Reached after the filter-key type check passes.
Common situations: 'sources' accidentally set to a string while 'sources!' is a list; configuration merge that converted the base list to a scalar; refactoring that left a stale scalar base.
Related errors
- {name} key {key} must be list, not {value.__class__.__name__
- Unrecognized action {action} in {name} key {regex_key}
- {name} key {excluded_key} must not be present prior to appl
- Found wildcard in {dependency_key} of {target} referring to
- Missing 'target_name' field in target.
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/3f5609a8bff1693a.
Report an issue: GitHub.