phacility/phabricator · error · Exception
Storage patch "%s" specifies it should apply in phase "%s",
Error message
Storage patch "%s" specifies it should apply in phase "%s", but this phase is unrecognized. Valid phases are: %s.
What it means
Storage patches are grouped into execution phases (defined by PhabricatorStoragePatch::getPhaseList(), currently 'default' and 'worker') so critical patches can run before workers restart during an upgrade. A patch that sets a 'phase' key with a value not in that list is a typo or an invented phase, and the loader aborts because ordering across phases cannot be validated.
Source
Thrown at src/infrastructure/storage/patch/PhabricatorSQLPatchList.php:157
if ($namespace != 'phabricator') {
throw new Exception(
pht(
"Only patches in the '%s' namespace may contain '%s' keys.",
'phabricator',
'legacy'));
}
} else {
$patch['legacy'] = false;
}
if (!array_key_exists('phase', $patch)) {
$patch['phase'] = $default_phase;
}
$patch_phase = $patch['phase'];
if (!isset($phases[$patch_phase])) {
throw new Exception(
pht(
'Storage patch "%s" specifies it should apply in phase "%s", '.
'but this phase is unrecognized. Valid phases are: %s.',
$full_key,
$patch_phase,
implode(', ', array_keys($phases))));
}
$last_key = $last_keys[$patch_phase];
if (!array_key_exists('after', $patch)) {
if ($last_key === null && $patch_phase === $default_phase) {
throw new Exception(
pht(
"Patch '%s' is missing key 'after', and is the first patch ".
"in the patch list '%s', so its application order can not be ".
"determined implicitly. The first patch in a patch list must ".
"list the patch or patches it depends on explicitly.",View on GitHub (pinned to 5720a38cfe)
Solutions
- Change the 'phase' value to one of the phases listed in the error message ('default' or 'worker').
- If ordinary ordering is fine, delete the 'phase' key entirely — absent means the default phase.
- Use PhabricatorStoragePatch::PHASE_DEFAULT / PHASE_WORKER literals rather than raw strings to avoid typos.
- Re-run 'bin/storage status' to confirm the list loads.
Example fix
// before
'20180101.daemon.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20180101.daemon.sql'),
'phase' => 'daemon',
),
// after
'20180101.daemon.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20180101.daemon.sql'),
'phase' => PhabricatorStoragePatch::PHASE_WORKER,
), Defensive patterns
Strategy: validation
Validate before calling
// Validate phase literals against the engine's own list:
$valid_phases = array_fuse(PhabricatorStoragePatch::getPhaseList());
foreach ((new MyApplicationPatchList())->getPatches() as $key => $patch) {
if (isset($patch['phase']) && !isset($valid_phases[$patch['phase']])) {
throw new Exception("Patch {$key} has unknown phase '{$patch['phase']}'");
}
} Prevention
- Use the constants PhabricatorStoragePatch::PHASE_DEFAULT / PHASE_WORKER instead of raw strings.
- Omit 'phase' entirely unless you specifically need worker-phase execution.
When it happens
Trigger: A patch spec contains 'phase' => 'something' where 'something' is not exactly 'default' or 'worker' (e.g. 'default ', 'Worker', 'compat', 'setup'). Fires during PhabricatorSQLPatchList::buildAllPatches() on any storage-management command.
Common situations: Guessing phase names when adding a patch to a fork; copying a phase name from an incompatible Phabricator version where the phase list differed; case or whitespace mistakes in the literal.
Related errors
- %s '%s' has a patch, '%s', with an unknown property, '%s'.Pa
- %s '%s' has a patch with a numeric key, '%s'. Patches must u
- %s '%s' has a patch with a colon in the key name, '%s'. Patc
- %s '%s' has a patch '%s' which duplicates an existing patch
- Only patches in the '%s' namespace may contain '%s' keys.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/5a05020a10743ba9.
Report an issue: GitHub.