{"record":{"id":"42fa7ce8a04fc6b4","repo":"nodejs/node","slug":"undefined-variable-s-in-s","errorCode":null,"errorMessage":"Undefined variable %s in %s","messagePattern":"Undefined variable (.+?) in (.+?)","errorType":"exception","errorClass":"GypError","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/input.py","lineNumber":1005,"sourceCode":"                    contents,\n                    build_file_dir,\n                )\n                replacement = cached_value\n\n        elif contents not in variables:\n            if contents[-1] in [\"!\", \"/\"]:\n                # In order to allow cross-compiles (nacl) to happen more naturally,\n                # we will allow references to >(sources/) etc. to resolve to\n                # and empty list if undefined. This allows actions to:\n                # 'action!': [\n                #   '>@(_sources!)',\n                # ],\n                # 'action/': [\n                #   '>@(_sources/)',\n                # ],\n                replacement = []\n            else:\n                raise GypError(\"Undefined variable \" + contents + \" in \" + build_file)\n        else:\n            replacement = variables[contents]\n\n        if isinstance(replacement, bytes) and not isinstance(replacement, str):\n            replacement = replacement.decode(\"utf-8\")  # done on Python 3 only\n        if isinstance(replacement, list):\n            for item in replacement:\n                if isinstance(item, bytes) and not isinstance(item, str):\n                    item = item.decode(\"utf-8\")  # done on Python 3 only\n                if not contents[-1] == \"/\" and type(item) not in (str, int):\n                    raise GypError(\n                        \"Variable \"\n                        + contents\n                        + \" must expand to a string or list of strings; \"\n                        + \"list contains a \"\n                        + item.__class__.__name__\n                    )\n            # Run through the list and handle variable expansions in it.  Since","sourceCodeStart":987,"sourceCodeEnd":1023,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/input.py#L987-L1023","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n'defines': ['DEFINE=<(my_feature_flag)'],  // my_feature_flag undefined\n// after — define it in variables or .gypi\n'variables': { 'my_feature_flag%': '0' },\n'defines': ['DEFINE=<(my_feature_flag)'],","handlingStrategy":"validation","validationCode":"def check_var(name, variables, build_file):\n    assert name in variables or name[-1] in ('!', '/'), \\\n        f'Undefined GYP variable {name!r} in {build_file}'","typeGuard":"def is_defined_or_optional(name: str, variables: dict) -> bool:\n    return name in variables or name[-1] in ('!', '/')","tryCatchPattern":"try:\n    gyp.process_build_file(...)\nexcept gyp.input.GypError as e:\n    if str(e).startswith('Undefined variable'):\n        report_missing_variable(str(e))","preventionTips":["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."],"tags":["gyp","variables","undefined","build-config","expansion"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}