{"record":{"id":"ee7a9f876d2e33bd","repo":"nodejs/node","slug":"unable-to-find-a-valid-ninja-output-directory","errorCode":null,"errorMessage":"Unable to find a valid ninja output directory.","messagePattern":"Unable to find a valid ninja output directory\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"deps/v8/tools/vim/ninja_output.py","lineNumber":65,"sourceCode":"        path = os.path.join(out_path, config)\n        if os.path.exists(os.path.join(path, 'build.ninja')):\n          yield path\n\n  def approx_directory_mtime(path):\n    # This is a heuristic; don't recurse into subdirectories.\n    paths = [path] + [os.path.join(path, f) for f in os.listdir(path)]\n    return max(filter(None, [safe_mtime(p) for p in paths]))\n\n  def safe_mtime(path):\n    try:\n      return os.path.getmtime(path)\n    except OSError:\n      return None\n\n  try:\n    return max(generate_paths(), key=approx_directory_mtime)\n  except ValueError:\n    raise RuntimeError('Unable to find a valid ninja output directory.')\n\n\nif __name__ == '__main__':\n  if len(sys.argv) != 2:\n    raise RuntimeError('Expected a single path argument.')\n  print(GetNinjaOutputDirectory(sys.argv[1]))\n","sourceCodeStart":47,"sourceCodeEnd":72,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/v8/tools/vim/ninja_output.py#L47-L72","documentation":"Raised by GetNinjaOutputDirectory in deps/v8/tools/vim/ninja_output.py when generate_paths() yields no candidate build directories, so max(..., key=...) raises ValueError, which is caught and re-raised as this RuntimeError. It is used by V8's Vim syntastic/ale integration to locate the build output for clangd/compilation.","triggerScenarios":"Calling GetNinjaOutputDirectory(path) where no out/<config> or build output directory exists under the given project path; all generated candidate paths are empty so approx_directory_mtime has nothing to compare.","commonSituations":"Using the V8 Vim integration before running gn gen / ninja; pointing the script at a fresh checkout with no build artifacts; the build output lives in a non-standard location the heuristics don't search.","solutions":["Build first: run gn gen out/Release (or out/build) then ninja -C out/Release so an output directory exists.","Confirm the path passed to GetNinjaOutputDirectory is the V8 source root containing the out/ tree.","If using a custom output dir, create a symlink or adjust the heuristics in ninja_output.py to include it."],"exampleFix":"# before (no build output yet)\n:make\n# after\ngn gen out/Release && ninja -C out/Release\n# then re-run the Vim command","handlingStrategy":"validation","validationCode":"import os\ndef has_build_output(project_root: str) -> bool:\n    return any(os.path.isdir(os.path.join(project_root, d)) for d in ('out','build')) and \\\n           any(os.path.isdir(os.path.join(project_root, 'out', c)) for c in os.listdir(os.path.join(project_root, 'out'))) if os.path.isdir(os.path.join(project_root,'out')) else False","typeGuard":"null","tryCatchPattern":"from tools.vim.ninja_output import GetNinjaOutputDirectory\ntry:\n    out = GetNinjaOutputDirectory(project_root)\nexcept RuntimeError:\n    out = None\n    print('Build the project first: gn gen out/Release && ninja -C out/Release')","preventionTips":["Run gn gen + ninja before invoking the Vim integration.","Point the script at the source root containing out/.","Symlink non-standard output dirs into out/ for the heuristics to find them."],"tags":["v8","vim","ninja","build-output","tooling"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}