{"record":{"id":"e1d75d680edee551","repo":"nodejs/node","slug":"cycles-in-gyp-file-dependency-graph-detected-cy","errorCode":null,"errorMessage":"Cycles in .gyp file dependency graph detected:\n{cycles}","messagePattern":"Cycles in \\.gyp file dependency graph detected:\n(.+?)","errorType":"exception","errorClass":"DependencyGraphNode.CircularException","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/input.py","lineNumber":2036,"sourceCode":"            build_file_node.dependencies.append(root_node)\n            root_node.dependents.append(build_file_node)\n\n    flat_list = root_node.FlattenToList()\n\n    # If there's anything left unvisited, there must be a circular dependency\n    # (cycle).\n    if len(flat_list) != len(dependency_nodes):\n        if not root_node.dependents:\n            # If all files have dependencies, add the first file as a dependent\n            # of root_node so that the cycle can be discovered from root_node.\n            file_node = next(iter(dependency_nodes.values()))\n            file_node.dependencies.append(root_node)\n            root_node.dependents.append(file_node)\n        cycles = []\n        for cycle in root_node.FindCycles():\n            paths = [node.ref for node in cycle]\n            cycles.append(\"Cycle: %s\" % \" -> \".join(paths))\n        raise DependencyGraphNode.CircularException(\n            \"Cycles in .gyp file dependency graph detected:\\n\" + \"\\n\".join(cycles)\n        )\n\n\ndef DoDependentSettings(key, flat_list, targets, dependency_nodes):\n    # key should be one of all_dependent_settings, direct_dependent_settings,\n    # or link_settings.\n\n    for target in flat_list:\n        target_dict = targets[target]\n        build_file = gyp.common.BuildFile(target)\n\n        if key == \"all_dependent_settings\":\n            dependencies = dependency_nodes[target].DeepDependencies()\n        elif key == \"direct_dependent_settings\":\n            dependencies = dependency_nodes[target].DirectAndImportedDependencies(\n                targets\n            )","sourceCodeStart":2018,"sourceCodeEnd":2054,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/input.py#L2018-L2054","documentation":"The file-level analog of error 504. After building the .gyp-file dependency graph and flattening from root_node, if the flattened count != number of file nodes, a cycle exists among .gyp files. gyp attaches the first file to root_node if needed, enumerates cycles via FindCycles, and raises CircularException listing file-level cycles (fileA -> fileB -> fileA).","triggerScenarios":"Two or more .gyp files include/depend on each other in a ring at the file level (A.gyp depends on B.gyp which depends on A.gyp), detected by the length mismatch in VerifyNoGYPFileCircularDependencies.","commonSituations":"Splitting a monolithic .gyp into two files that both reference each other's targets; refactor that introduced mutual includes; cyclic includes via the dependencies arrays across files.","solutions":["Break the file-level ring by removing one cross-file dependency edge.","Move the contested target(s) into a single file or a third shared file so the dependency becomes one-directional.","Use settings propagation (all_dependent_settings) instead of a hard dependency if only settings are needed."],"exampleFix":"// before: a.gyp depends on b.gyp and b.gyp depends on a.gyp\n// move shared target into common.gyp; both depend on common.gyp only","handlingStrategy":"validation","validationCode":"# file-level cycle check\ndef file_cycle(file_deps):\n    color = {}\n    def dfs(n):\n        color[n] = 1\n        for m in file_deps.get(n, []):\n            if color.get(m) == 1: return True\n            if m not in color and dfs(m): return True\n        color[n] = 2\n        return False\n    return any(n not in color and dfs(n) for n in file_deps)\n","typeGuard":null,"tryCatchPattern":"try:\n    gyp.main(args)\nexcept gyp.input.DependencyGraphNode.CircularException as e:\n    if '.gyp file' in str(e): print('File-level include cycle'); raise","preventionTips":["Keep .gyp file includes acyclic (one direction).","Centralize shared targets in a leaf .gyp.","Review cross-file dependencies during refactor."],"tags":["gyp","dependency-graph","cycle","circular-dependency","build-config"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}