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.  Since

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Define the variable: add it to the 'variables' dict of the .gyp file, a .gypi include, or pass it via gyp -D name=value.
  2. Check the spelling and case of the variable name against where it is defined.
  3. If the reference is legitimately optional, append '!' or '/' (e.g. '>@(_sources!)') so an undefined value resolves to an empty list.
  4. 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

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


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