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
- Make the step return an existing group key (e.g. the key of the default/normal group) unless it needs its own section.
- 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.
- Fix typos: the string in getBuildStepGroupKey() must byte-for-byte equal some group's GROUPKEY.
- 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
- Add a unit test in every custom step extension asserting getBuildStepGroupKey() returns a key present in HarbormasterBuildStepGroup::getAllGroups().
- Register every custom group class in the phutil library map and regenerate the map before deploying.
- Rebase custom extensions after upstream upgrades; renamed GROUPKEY constants are a common breakage.
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
- No implementation is specified!
- No such implementation "%s" exists!
- No such variable '%s'!
- This object does not support builds with Buildkite.
- Object ("%s") does not implement interface "%s". Only object
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/4b6b998d9a2e6e08.
Report an issue: GitHub.