nodejs/node · error · Exception
Unable to open file %s
Error message
Unable to open file %s
What it means
analyzer.py's Config.Init raises Exception('Unable to open file ' + config_path) when open(config_path) throws OSError. The analyzer generator reads a JSON config (set via generator_flags['config_path']) describing which files changed and which targets to test; if the path doesn't exist or isn't readable, Init bails. (A separate ValueError handler covers JSON parse errors; this one is strictly the open() failure.)
Source
Thrown at tools/gyp/pylib/gyp/generator/analyzer.py:277
def __init__(self):
self.files = []
self.targets = set()
self.additional_compile_target_names = set()
self.test_target_names = set()
def Init(self, params):
"""Initializes Config. This is a separate method as it raises an exception
if there is a parse error."""
generator_flags = params.get("generator_flags", {})
config_path = generator_flags.get("config_path", None)
if not config_path:
return
try:
f = open(config_path)
config = json.load(f)
f.close()
except OSError:
raise Exception("Unable to open file " + config_path)
except ValueError as e:
raise Exception("Unable to parse config file " + config_path + str(e))
if not isinstance(config, dict):
raise Exception("config_path must be a JSON file containing a dictionary")
self.files = config.get("files", [])
self.additional_compile_target_names = set(
config.get("additional_compile_targets", [])
)
self.test_target_names = set(config.get("test_targets", []))
def _WasBuildFileModified(build_file, data, files, toplevel_dir):
"""Returns true if the build file |build_file| is either in |files| or
one of the files included by |build_file| is in |files|. |toplevel_dir| is
the root of the source tree."""
if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files:
if debug:
print("gyp file modified", build_file)View on GitHub (pinned to 1b2de5e052)
Solutions
- Verify config_path exists and is readable before invoking gyp: `os.path.isfile(config_path)`.
- Use an absolute path for config_path to avoid cwd ambiguity.
- Ensure the upstream step that produces the analyzer JSON actually ran and wrote to the expected location.
- Check file permissions if running under a different user.
Example fix
# before python gyp -f analyzer --generator_flag=config_path=changed.json # (changed.json does not exist) # after # generate the file first, then pass an absolute path python write_analyzer_config.py /abs/changed.json python gyp -f analyzer --generator_flag=config_path=/abs/changed.json
Defensive patterns
Strategy: validation
Validate before calling
import os
def load_analyzer_config(config_path):
if not config_path or not os.path.isfile(config_path):
raise SystemExit('analyzer config_path missing or unreadable: %r' % config_path)
with open(config_path) as f:
return json.load(f) Type guard
def config_path_readable(path: str) -> bool:
import os
return bool(path) and os.path.isfile(path) and os.access(path, os.R_OK) Try / catch
try:
config.Init(params)
except Exception as e:
if 'Unable to open file' in str(e):
# regenerate the changed-files JSON, then retry
write_analyzer_config()
config.Init(params) Prevention
- Use an absolute path for the analyzer config_path generator flag.
- Generate the changed-files JSON in a prior build step and assert it exists.
- Verify read permissions when running gyp under a service account.
When it happens
Trigger: Invoking gyp -f analyzer with --generator-flag=config_path=<missing.json>; passing a relative path that doesn't resolve under gyp's cwd; permission denied on the config file.
Common situations: CI scripts that write the changed-files JSON to a temp path and pass a stale/wrong location; cross-platform path separators; the analyzer config not being generated by an earlier step.
Related errors
- Unable to parse config file %s%s
- config_path must be a JSON file containing a dictionary
- Must specify files to analyze via config_path generator flag
- Key '%s' repeated at level %s with key path '%s'
- %s does not evaluate to a dictionary.
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/4cfdb3dda7492774.
Report an issue: GitHub.