nodejs/node · error · GypError
{name} key {excluded_key} must not be present prior to appl
Error message
{name} key {excluded_key} must not be present prior to applying exclusion/regex filters for {list_key} What it means
After applying exclusion/regex filters, gyp creates an output list named '<list_key>_excluded' (e.g. 'sources_excluded'). If that output key ALREADY exists in the dict before filtering, gyp raises GypError because it would clobber user data / indicate a double-processing mistake.
Source
Thrown at tools/gyp/pylib/gyp/input.py:2632
# Even if the regex matches, nothing will change so continue
# (regex searches are expensive).
continue
if pattern_re.search(list_item):
# Regular expression match.
list_actions[index] = action_value
# The "whatever/" list is no longer needed, dump it.
del the_dict[regex_key]
# Add excluded items to the excluded list.
#
# Note that exclude_key ("sources!") is different from excluded_key
# ("sources_excluded"). The exclude_key list is input and it was already
# processed and deleted; the excluded_key list is output and it's about
# to be created.
excluded_key = list_key + "_excluded"
if excluded_key in the_dict:
raise GypError(
name + " key " + excluded_key + " must not be present prior "
" to applying exclusion/regex filters for " + list_key
)
excluded_list = []
# Go backwards through the list_actions list so that as items are deleted,
# the indices of items that haven't been seen yet don't shift. That means
# that things need to be prepended to excluded_list to maintain them in the
# same order that they existed in the_list.
for index in range(len(list_actions) - 1, -1, -1):
if list_actions[index] == 0:
# Dump anything with action 0 (exclude). Keep anything with action 1
# (include) or -1 (no include or exclude seen for the item).
excluded_list.insert(0, the_list[index])
del the_list[index]
# If anything was excluded, put the excluded list into the_dict atView on GitHub (pinned to 1b2de5e052)
Solutions
- Remove the pre-existing '_excluded' key; it is generated output, not input.
- Do not declare 'sources_excluded' (or any '<key>_excluded') by hand.
- Ensure the filter pass is invoked once per dict (avoid double processing).
Example fix
// before: { 'sources': [...], 'sources!': [...], 'sources_excluded': [...] }
// after: { 'sources': [...], 'sources!': [...] } // gyp creates sources_excluded Defensive patterns
Strategy: validation
Validate before calling
for k in list(the_dict):
if k[-1:] in ('!', '/'):
base = k[:-1]
assert (base + '_excluded') not in the_dict, 'pre-existing %s_excluded' % base
Try / catch
try:
gyp.main(args)
except gyp.input.GypError as e:
if 'must not be present prior' in str(e): print('Remove the hand-written _excluded key'); raise Prevention
- Never declare '<key>_excluded' manually; it is generated output.
- Run the filter pass once per dict.
- Audit includes for stale excluded lists.
When it happens
Trigger: the_dict already contains a key like 'sources_excluded' at the moment ProcessListFiltersInDict runs for the matching 'sources'/'sources!' pair.
Common situations: Manually pre-declaring 'sources_excluded' thinking it is input; running the filter pass twice on the same dict; an include file that ships a pre-built excluded list; merging artifacts from a prior partial run.
Related errors
- {name} key {key} must be list, not {value.__class__.__name__
- {name} key {list_key} must be list, not {value.__class__.__n
- Unrecognized action {action} in {name} key {regex_key}
- 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/cb879e1fc33d59de.
Report an issue: GitHub.