nodejs/node · error · GypError
Undefined variable %s in %s
Error message
Undefined variable %s in %s
What it means
During variable expansion (<(), >(), ^()), if the referenced name is not a key in the current variables dict, GYP raises this GypError. The only exception is when the name ends with '!' or '/' — those forms are allowed to resolve to an empty list to support optional cross-compile references like >@(_sources!). Any other undefined name is a hard error, naming the variable and the build file.
Source
Thrown at tools/gyp/pylib/gyp/input.py:1005
contents,
build_file_dir,
)
replacement = cached_value
elif contents not in variables:
if contents[-1] in ["!", "/"]:
# In order to allow cross-compiles (nacl) to happen more naturally,
# we will allow references to >(sources/) etc. to resolve to
# and empty list if undefined. This allows actions to:
# 'action!': [
# '>@(_sources!)',
# ],
# 'action/': [
# '>@(_sources/)',
# ],
replacement = []
else:
raise GypError("Undefined variable " + contents + " in " + build_file)
else:
replacement = variables[contents]
if isinstance(replacement, bytes) and not isinstance(replacement, str):
replacement = replacement.decode("utf-8") # done on Python 3 only
if isinstance(replacement, list):
for item in replacement:
if isinstance(item, bytes) and not isinstance(item, str):
item = item.decode("utf-8") # done on Python 3 only
if not contents[-1] == "/" and type(item) not in (str, int):
raise GypError(
"Variable "
+ contents
+ " must expand to a string or list of strings; "
+ "list contains a "
+ item.__class__.__name__
)
# Run through the list and handle variable expansions in it. SinceView on GitHub (pinned to 1b2de5e052)
Solutions
- Define the variable: add it to the 'variables' dict of the .gyp file, a .gypi include, or pass it via gyp -D name=value.
- Check the spelling and case of the variable name against where it is defined.
- If the reference is legitimately optional, append '!' or '/' (e.g. '>@(_sources!)') so an undefined value resolves to an empty list.
- Confirm the phase: '<' is early, '>' is late, '^' is latelate — a variable only available later must be referenced with the matching symbol.
Example fix
// before
'defines': ['DEFINE=<(my_feature_flag)'], // my_feature_flag undefined
// after — define it in variables or .gypi
'variables': { 'my_feature_flag%': '0' },
'defines': ['DEFINE=<(my_feature_flag)'], Defensive patterns
Strategy: validation
Validate before calling
def check_var(name, variables, build_file):
assert name in variables or name[-1] in ('!', '/'), \
f'Undefined GYP variable {name!r} in {build_file}' Type guard
def is_defined_or_optional(name: str, variables: dict) -> bool:
return name in variables or name[-1] in ('!', '/') Try / catch
try:
gyp.process_build_file(...)
except gyp.input.GypError as e:
if str(e).startswith('Undefined variable'):
report_missing_variable(str(e)) Prevention
- Keep a single common.gypi that defines shared variables; include it everywhere.
- Use the matching expansion symbol for the phase (< early, > late, ^ latelate).
- Append '!' or '/' for genuinely optional references.
When it happens
Trigger: A .gyp file references '<(OS)' but OS was never defined in this scope (no automatic variable, no -D, no parent 'variables'); a typo in the variable name; referencing a target-scope variable during the early phase before it is set; missing or misspelled .gypi include that should have defined the variable.
Common situations: Forgetting to include a common.gypi that defines shared variables; typo like '<(oS)' vs '<(OS)'; using a late-phase '>' variable in an early-phase '<' context where it is not yet populated; renaming a variable in one place but not all references; conditional variable only set in one branch.
Related errors
- Variable %s must expand to a string or list of strings; foun
- Variable expansion in this context permits str and int only,
- Variable %s must expand to a string or list of strings; list
- Variable expansion in this context permits str and int only,
- Variable expansion in this context permits strings and lists
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/42fa7ce8a04fc6b4.
Report an issue: GitHub.