{"record":{"id":"9cf9944a21f8986c","repo":"nodejs/node","slug":"unknown-ast-node-at-key-path-s-s","errorCode":null,"errorMessage":"Unknown AST node at key path '%s': %s","messagePattern":"Unknown AST node at key path '(.+?)': (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/input.py","lineNumber":218,"sourceCode":"                    + \" with key path '\"\n                    + \".\".join(keypath)\n                    + \"'\"\n                )\n            kp = list(keypath)  # Make a copy of the list for descending this node.\n            kp.append(key)\n            dict[key] = CheckNode(value, kp)\n        return dict\n    elif isinstance(node, ast.List):\n        children = []\n        for index, child in enumerate(node.elts):\n            kp = list(keypath)  # Copy list.\n            kp.append(repr(index))\n            children.append(CheckNode(child, kp))\n        return children\n    elif isinstance(node, ast.Str):\n        return node.s\n    else:\n        raise TypeError(\n            \"Unknown AST node at key path '\" + \".\".join(keypath) + \"': \" + repr(node)\n        )\n\n\ndef LoadOneBuildFile(build_file_path, data, aux_data, includes, is_target, check):\n    if build_file_path in data:\n        return data[build_file_path]\n\n    if os.path.exists(build_file_path):\n        build_file_contents = open(build_file_path, encoding=\"utf-8\").read()\n    else:\n        raise GypError(f\"{build_file_path} not found (cwd: {os.getcwd()})\")\n\n    build_file_data = None\n    try:\n        if check:\n            build_file_data = CheckedEval(build_file_contents)\n        else:","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/input.py#L200-L236","documentation":"Raised as a TypeError by CheckNode during checked .gyp evaluation when the AST contains a node type other than Dict, List, or Str. Gyp's strict check mode only permits string literals, lists, and dicts at the value level; anything else (numbers, booleans, None, name references, arithmetic, function calls) is rejected because gyp files are meant to be declarative data.","triggerScenarios":"A .gyp file evaluated with check=True contains a numeric literal, a boolean, a bare identifier, a unary/binary expression, or a function call at a value position. CheckNode's isinstance chain falls through to the `else` at input.py:219.","commonSituations":"Using a number directly (e.g. 'version': 3) instead of a string ('version': '3'); referencing a variable by name; pasting Python expressions into a gyp file; using True/False/None literals.","solutions":["Convert non-string scalar values to quoted string literals (e.g. 3 -> '3', true -> 'true').","Remove variable references and Python expressions; gyp files must be pure literal data in check mode.","If you need computed values, use gyp variables and conditionals rather than inline expressions."],"exampleFix":"// before\n'targets': [{ 'target_name': 'foo', 'version': 3, 'enabled': true }]\n// after\n'targets': [{ 'target_name': 'foo', 'version': '3', 'enabled': 'true' }]","handlingStrategy":"validation","validationCode":"import ast\n_ALLOWED = (ast.Dict, ast.List, ast.Str)\nfor fn in gyp_files:\n    tree = ast.parse(open(fn).read())\n    for node in ast.walk(tree):\n        if not isinstance(node, (ast.Module, ast.Expr)+_ALLOWED) and not isinstance(ast.dump(node), str):\n            pass\ndef check(node):\n    if isinstance(node, ast.Dict) or isinstance(node, ast.List):\n        return True\n    return isinstance(node, ast.Str)","typeGuard":"import ast\ndef is_allowed_node(node) -> bool:\n    return isinstance(node, (ast.Dict, ast.List, ast.Str))","tryCatchPattern":null,"preventionTips":["Use only string literals, lists, and dicts in checked .gyp files.","Quote numeric/boolean values rather than using bare literals."],"tags":["gyp","input","ast","type-error","config"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}