{"record":{"id":"80fd333c248a7e8c","repo":"nodejs/node","slug":"unable-to-find-targets-in-build-file-s","errorCode":null,"errorMessage":"Unable to find targets in build file %s","messagePattern":"Unable to find targets in build file (.+?)","errorType":"exception","errorClass":"GypError","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/input.py","lineNumber":439,"sourceCode":"\n    # Do a first round of toolsets expansion so that conditions can be defined\n    # per toolset.\n    ProcessToolsetsInDict(build_file_data)\n\n    # Apply \"pre\"/\"early\" variable expansions and condition evaluations.\n    ProcessVariablesAndConditionsInDict(\n        build_file_data, PHASE_EARLY, variables, build_file_path\n    )\n\n    # Since some toolsets might have been defined conditionally, perform\n    # a second round of toolsets expansion now.\n    ProcessToolsetsInDict(build_file_data)\n\n    # Look at each project's target_defaults dict, and merge settings into\n    # targets.\n    if \"target_defaults\" in build_file_data:\n        if \"targets\" not in build_file_data:\n            raise GypError(\"Unable to find targets in build file %s\" % build_file_path)\n\n        index = 0\n        while index < len(build_file_data[\"targets\"]):\n            # This procedure needs to give the impression that target_defaults is\n            # used as defaults, and the individual targets inherit from that.\n            # The individual targets need to be merged into the defaults.  Make\n            # a deep copy of the defaults for each target, merge the target dict\n            # as found in the input file into that copy, and then hook up the\n            # copy with the target-specific data merged into it as the replacement\n            # target dict.\n            old_target_dict = build_file_data[\"targets\"][index]\n            new_target_dict = gyp.simple_copy.deepcopy(\n                build_file_data[\"target_defaults\"]\n            )\n            MergeDicts(\n                new_target_dict, old_target_dict, build_file_path, build_file_path\n            )\n            build_file_data[\"targets\"][index] = new_target_dict","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/input.py#L421-L457","documentation":"Raised as a GypError by LoadTargetBuildFile when a .gyp file declares a 'target_defaults' block but no 'targets' block. target_defaults is meant to supply shared defaults that individual targets inherit; defining defaults without any targets to apply them to is treated as a structural error, since the file would produce no output.","triggerScenarios":"A target .gyp file contains 'target_defaults' but no 'targets' key. The check at input.py:442 fires because target_defaults is only processed when targets exist to receive the defaults.","commonSituations":"Splitting a .gyp and forgetting to add the 'targets' array; a refactor that moved targets into another file but left target_defaults behind; misunderstanding that target_defaults supplements rather than replaces targets.","solutions":["Add a 'targets' array to the .gyp file (even if some values come from target_defaults).","If the file is meant only to hold shared defaults, convert it to a .gypi include consumed by other .gyp files rather than a standalone target file.","Move target_defaults into a common.gypi that is included where targets actually live."],"exampleFix":"// before (foo.gyp)\n{\n  'target_defaults': { 'include_dirs': ['include'] }\n}\n// after\n{\n  'target_defaults': { 'include_dirs': ['include'] },\n  'targets': [\n    { 'target_name': 'foo', 'type': 'static_library', 'sources': ['foo.cc'] }\n  ]\n}","handlingStrategy":"validation","validationCode":"if 'target_defaults' in build_file_data and 'targets' not in build_file_data:\n    raise ValueError('file has target_defaults but no targets; add a targets array')","typeGuard":"def defaults_have_targets(data) -> bool:\n    return 'target_defaults' not in data or 'targets' in data","tryCatchPattern":null,"preventionTips":["Always include a 'targets' array when defining 'target_defaults'.","Move pure defaults into a .gypi include consumed by target-bearing files."],"tags":["gyp","input","schema","target-defaults","config","validation"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}