phacility/phabricator · error · Exception
Storage patch "%s" specifies a "@phase" value ("%s"), but it
Error message
Storage patch "%s" specifies a "@phase" value ("%s"), but it already has a specified phase ("%s"). Patches may not specify multiple phases. What it means
A PHP patch file may declare its phase exactly once. The header parser remembers the phase after the first '// @phase' line; if a second, different '@phase' attribute appears later in the header block, the loader throws because a single patch cannot execute in two phases.
Source
Thrown at src/infrastructure/storage/patch/PhabricatorSQLPatchList.php:312
'Storage patch "%s" specifies a "@phase" attribute with '.
'no phase value. Phase attributes must specify a value, '.
'like "@phase default".',
$patch_name));
}
if (!isset($phase_map[$phase_name])) {
throw new Exception(
pht(
'Storage patch "%s" specifies a "@phase" value ("%s"), '.
'but this is not a recognized phase. Valid phases '.
'are: %s.',
$patch_name,
$phase_name,
implode(', ', $phase_list)));
}
if (isset($attributes['phase'])) {
throw new Exception(
pht(
'Storage patch "%s" specifies a "@phase" value ("%s"), '.
'but it already has a specified phase ("%s"). Patches '.
'may not specify multiple phases.',
$patch_name,
$phase_name,
$attributes['phase']));
}
$attributes[$attr_key] = $phase_name;
break;
default:
throw new Exception(
pht(
'Storage patch "%s" specifies attribute "%s", but this '.
'attribute is unknown.',
$patch_name,
$attr_key));View on GitHub (pinned to 5720a38cfe)
Solutions
- Keep only one '// @phase' line in the header block and delete the other.
- Verify the surviving value is the intended phase ('default' or 'worker').
- Re-run 'bin/storage status' to confirm the file parses.
Example fix
// before <?php // @phase worker // @phase default // Migrates job tables. // after <?php // @phase worker // Migrates job tables.
Defensive patterns
Strategy: validation
Validate before calling
// A header block must contain at most one '@phase' line:
$lines = file($patch_path);
$phase_lines = preg_grep('/^\s*\/\/\s*@phase\s+\S+/', $lines);
if (count($phase_lines) > 1) {
throw new Exception('Patch header declares more than one phase');
} Prevention
- Edit the existing '@phase' line in place; never add a second one.
- After resolving merge conflicts in patch headers, grep the file for duplicate '@phase' lines.
When it happens
Trigger: The leading comment block of a .php patch contains two '// @phase ...' lines — e.g. a merged patch file where both contributors added a phase annotation, or an edited header where the old line was left in place.
Common situations: Merge conflicts in patch headers resolved by keeping both lines; editing an existing '@phase' line by duplicating it and editing the copy instead of the original.
Related errors
- Storage patch "%s" specifies a "@phase" attribute with no ph
- Storage patch "%s" specifies a "@phase" value ("%s"), but th
- Storage patch "%s" specifies it should apply in phase "%s",
- Storage patch "%s" executes in phase "%s", but depends on pa
- Storage patch "%s" specifies attribute "%s", but this attrib
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/41cb6fe6d7b413e5.
Report an issue: GitHub.