phacility/phabricator · error · Exception

Build step "%s" has step group key "%s", but no step group w

Error message

Build step "%s" has step group key "%s", but no step group with that key exists.

What it means

The 'Add Step' screen enumerates every registered build step implementation (HarbormasterBuildStepImplementation::getImplementations()) and groups them by getBuildStepGroupKey(); the keys must correspond to a HarbormasterBuildStepGroup subclass discovered by PhutilClassMapQuery (each group exposes a GROUPKEY constant). This exception means some implementation returns a group key for which no group class exists, so the Add Step page cannot be rendered at all.

Source

Thrown at src/applications/harbormaster/controller/HarbormasterStepAddController.php:33

          PhabricatorPolicyCapability::CAN_EDIT,
        ))
      ->executeOne();
    if (!$plan) {
      return new Aphront404Response();
    }

    $plan_id = $plan->getID();
    $cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
    $plan_title = pht('Plan %d', $plan_id);

    $all = HarbormasterBuildStepImplementation::getImplementations();
    $all = msort($all, 'getName');

    $all_groups = HarbormasterBuildStepGroup::getAllGroups();
    foreach ($all as $impl) {
      $group_key = $impl->getBuildStepGroupKey();
      if (empty($all_groups[$group_key])) {
        throw new Exception(
          pht(
            'Build step "%s" has step group key "%s", but no step group '.
            'with that key exists.',
            get_class($impl),
            $group_key));
      }
    }

    $groups = mgroup($all, 'getBuildStepGroupKey');
    $boxes = array();

    $enabled_groups = HarbormasterBuildStepGroup::getAllEnabledGroups();
    foreach ($enabled_groups as $group) {
      $list = id(new PHUIObjectItemListView())
        ->setNoDataString(
          pht('This group has no available build steps.'));

      $steps = idx($groups, $group->getGroupKey(), array());

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Make the step return an existing group key (e.g. the key of the default/normal group) unless it needs its own section.
  2. If a new section is intended, define a HarbormasterBuildStepGroup subclass with the matching GROUPKEY constant, load it via the library class map (phutil library map regeneration), and clear the class cache.
  3. Fix typos: the string in getBuildStepGroupKey() must byte-for-byte equal some group's GROUPKEY.
  4. After fixing, reload the Add Step page; the exception is per-request, no data is affected.

Example fix

// before (custom step)
public function getBuildStepGroupKey() {
  return 'mycustom';
}

// after (custom step reuses an existing group)
public function getBuildStepGroupKey() {
  return HarbormasterNormalBuildStepGroup::GROUPKEY;
}

// after (or register the group it wants)
final class MyCustomBuildStepGroup extends HarbormasterBuildStepGroup {
  const GROUPKEY = 'mycustom';
  public function getGroupName() { return pht('Custom Steps'); }
  public function getGroupOrder() { return 9000; }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Extension boot check: fail at startup, not on the Add Step page
$all_groups = HarbormasterBuildStepGroup::getAllGroups();
foreach (HarbormasterBuildStepImplementation::getImplementations() as $impl) {
  if (empty($all_groups[$impl->getBuildStepGroupKey()])) {
    throw new PhutilProxyException('bad step group', ...); // during extension init
  }
}

Type guard

function stepGroupKeyIsRegistered($key) {
  return array_key_exists($key, HarbormasterBuildStepGroup::getAllGroups());
}
// usage in the step:
public function getBuildStepGroupKey() {
  $key = 'mycustom';
  if (!stepGroupKeyIsRegistered($key)) {
    return HarbormasterNormalBuildStepGroup::GROUPKEY;
  }
  return $key;
}

Prevention

When it happens

Trigger: A custom step implementation whose getBuildStepGroupKey() returns a misspelled or invented key (e.g. 'custom/group' instead of an existing GROUPKEY); a custom group class that is not loaded by the library class map (so the key never registers); an upgrade that renamed a group key while an out-of-tree step still returns the old one.

Common situations: Deploying a custom Phabricator extension that adds a step but forgets the matching group class, or forgets to add the class to the library map; running an unrebased fork after upstream renamed group keys.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/4b6b998d9a2e6e08. Report an issue: GitHub.