nodejs/node · error · MBErr

Phase doesn't exist for on

Error message

Phase %s doesn't exist for %s on %s

What it means

Thrown by V8/Chromium's MB (meta-build) wrapper when a builder's entry in the mb config is a phased dict (e.g. {"x86": "...", "x64": "..."}) and the value passed via --phase is not one of its keys. MB coerces the phase to str() before the lookup, so the comparison is against the dict's string keys.

Solutions

  1. Open the mb config file (path referenced by --config-file) and list the valid phase keys for that builder.
  2. Re-run MB with one of those literal phase keys via --phase.
  3. If the builder shouldn't be phased, change its config entry from a dict to a flat string.

Example fix

// before
v8/tools/mb/mb.py gen -m client.v8 -b 'V8 Linux - builder' --phase x86
// after (phase 'x86' not in dict; use a real key)
v8/tools/mb/mb.py gen -m client.v8 -b 'V8 Linux - builder' --phase x64
Defensive patterns

Strategy: validation

Validate before calling

# Before invoking MB, confirm the phase is valid for the resolved config.
config = resolve_builder_config(builder_group, builder)  # from the mb config file
if isinstance(config, dict):
    assert str(phase) in config, (
        f"phase {phase!r} not in {sorted(config.keys())}")
else:
    assert phase is None, "non-phased builder; do not pass --phase"

Prevention

When it happens

Trigger: Running `mb.py <subcmd> -m <builder_group> -b <builder> --phase <X>` where builder_groups[group][builder] resolves to a dict and <X> is not a key of that dict.

Common situations: CI recipe passes a stale/renamed phase identifier; a new phased builder was added but the bot wasn't updated; integer-vs-string confusion because the phase is stringified before lookup.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/37e965d0737fae7a. Report an issue: GitHub.

Appendix: source

Thrown at deps/v8/tools/mb/mb.py:626

    if not self.args.builder_group in self.builder_groups:
      raise MBErr('Builder groups name "%s" not found in "%s"' %
                  (self.args.builder_group, self.args.config_file))

    config = _v8_builder_fallback(
        self.args.builder, self.builder_groups[self.args.builder_group])

    if not config:
      raise MBErr(
        'Builder name "%s"  not found under builder_groups[%s] in "%s"' %
        (self.args.builder, self.args.builder_group, self.args.config_file))

    if isinstance(config, dict):
      if self.args.phase is None:
        raise MBErr('Must specify a build --phase for %s on %s' %
                    (self.args.builder, self.args.builder_group))
      phase = str(self.args.phase)
      if phase not in config:
        raise MBErr('Phase %s doesn\'t exist for %s on %s' %
                    (phase, self.args.builder, self.args.builder_group))
      return config[phase]

    if self.args.phase is not None:
      raise MBErr('Must not specify a build --phase for %s on %s' %
                  (self.args.builder, self.args.builder_group))
    return config

  def FlattenConfig(self, config):
    mixins = self.configs[config]
    vals = self.DefaultVals()

    visited = []
    self.FlattenMixins(mixins, vals, visited)
    return vals

  def DefaultVals(self):
    return {

View on GitHub (pinned to 1b2de5e052)