{"record":{"id":"d4b743d4569abdeb","repo":"nodejs/node","slug":"failed-to-find-buildtools-directory-for-checkdep","errorCode":null,"errorMessage":"Failed to find //buildtools directory for checkdeps","messagePattern":"Failed to find //buildtools directory for checkdeps","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"deps/v8/PRESUBMIT.py","lineNumber":179,"sourceCode":"  return results\n\n\n\ndef _CheckUnwantedDependencies(input_api, output_api):\n  \"\"\"Runs checkdeps on #include statements added in this\n  change. Breaking - rules is an error, breaking ! rules is a\n  warning.\n  \"\"\"\n  # We need to wait until we have an input_api object and use this\n  # roundabout construct to import checkdeps because this file is\n  # eval-ed and thus doesn't have __file__.\n  original_sys_path = sys.path\n  try:\n    root = input_api.PresubmitLocalPath()\n    if not os.path.exists(os.path.join(root, 'buildtools')):\n      root = os.path.dirname(root)\n      if not os.path.exists(os.path.join(root, 'buildtools')):\n        raise RuntimeError(\n            \"Failed to find //buildtools directory for checkdeps\")\n    sys.path = sys.path + [\n        input_api.os_path.join(root, 'buildtools', 'checkdeps')\n    ]\n    import checkdeps\n    from cpp_checker import CppChecker\n    from rules import Rule\n  finally:\n    # Restore sys.path to what it was before.\n    sys.path = original_sys_path\n\n  def _FilesImpactedByDepsChange(files):\n    all_files = [f.AbsoluteLocalPath() for f in files]\n    deps_files = [p for p in all_files if IsDepsFile(p)]\n    impacted_files = union([_CollectImpactedFiles(path) for path in deps_files])\n    impacted_file_objs = [ImpactedFile(path) for path in impacted_files]\n    return impacted_file_objs\n","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/v8/PRESUBMIT.py#L161-L197","documentation":"V8's PRESUBMIT.py wires up the checkdeps include-rule linter by locating the //buildtools/checkdeps package. It looks for a 'buildtools' dir in the current presubmit path, then one level up; if neither exists it raises RuntimeError because checkdeps can't be imported and dependency rules can't be evaluated.","triggerScenarios":"Raised in _CheckNoApiUsage/_CheckDeps when `os.path.exists(input_api.PresubmitLocalPath()/buildtools)` and `os.path.exists(dirname(PresubmitLocalPath())/buildtools)` are both false — i.e. the presubmit is run from a checkout that doesn't contain buildtools.","commonSituations":"Running V8's presubmit on a standalone V8 checkout fetched without its DEPS (gclient sync skipped); running PRESUBMIT.py from inside Node's deps/v8 where buildtools lives at the Node root, two levels up, not one; vendoring V8 into another repo without bringing buildtools along.","solutions":["Run `gclient sync` (or `gclient sync --deps=v8`) so buildtools is fetched next to v8.","Run the presubmit from the repo root that actually contains buildtools, not a subdirectory.","If you vendored v8 manually, also vendor the matching buildtools directory at the expected level."],"exampleFix":"# before: standalone v8 checkout without DEPS\npython deps/v8/PRESUBMIT.py\n# after\ngclient sync\npython deps/v8/PRESUBMIT.py","handlingStrategy":"validation","validationCode":"import os\nroot = os.getcwd()\nassert os.path.isdir(os.path.join(root,'buildtools')) or os.path.isdir(os.path.join(os.path.dirname(root),'buildtools')), 'run gclient sync to fetch buildtools before presubmit'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always `gclient sync` so buildtools is fetched alongside v8.","Run PRESUBMIT.py from the checkout root that owns buildtools."],"tags":["v8","presubmit","buildtools","checkout","lint"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}