nodejs/node · error · MBErr

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

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.

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)

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.