phacility/phabricator · error · Exception
Patch '%s' is missing key '%s'. Every patch must have a type
Error message
Patch '%s' is missing key '%s'. Every patch must have a type.
What it means
Every patch must declare how it executes via a 'type' key, because the storage engine dispatches on it: 'db' creates a database, 'sql' runs a .sql file, 'php' runs a PHP script. A patch without a type cannot be applied, so the loader rejects the whole list.
Source
Thrown at src/infrastructure/storage/patch/PhabricatorSQLPatchList.php:196
} else {
if ($last_key === null) {
$patch['after'] = array();
} else {
$patch['after'] = array($last_key);
}
}
}
$last_keys[$patch_phase] = $full_key;
foreach ($patch['after'] as $after_key => $after) {
if (strpos($after, ':') === false) {
$patch['after'][$after_key] = $namespace.':'.$after;
}
}
$type = idx($patch, 'type');
if (!$type) {
throw new Exception(
pht(
"Patch '%s' is missing key '%s'. Every patch must have a type.",
"{$namespace}:{$key}",
'type'));
}
switch ($type) {
case 'db':
case 'sql':
case 'php':
break;
default:
throw new Exception(
pht(
"Patch '%s' has unknown patch type '%s'.",
"{$namespace}:{$key}",
$type));
}View on GitHub (pinned to 5720a38cfe)
Solutions
- Add 'type' => 'sql' (or 'php' / 'db') to the patch entry named in the message.
- Match the type to the file: .sql files -> 'sql', PHP migration scripts -> 'php', bare database creation -> 'db'.
- Re-run 'bin/storage status' to confirm the list loads.
Example fix
// before
'20180101.widget.sql' => array(
'name' => $this->getPatchPath('20180101.widget.sql'),
),
// after
'20180101.widget.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20180101.widget.sql'),
), Defensive patterns
Strategy: validation
Validate before calling
// Check every patch declares one of the three known types:
foreach ((new MyApplicationPatchList())->getPatches() as $key => $patch) {
if (empty($patch['type'])) {
throw new Exception("Patch '{$key}' is missing its 'type' key");
}
} Prevention
- Prefer buildPatchesFromDirectory() over hand-written entries — it fills in 'type' and 'name' from the file extension.
- When writing entries by hand, add 'type' in the same edit as 'name'.
When it happens
Trigger: A patch entry in getPatches() omits 'type' or sets it to a falsy value ('' or null). Common when hand-writing an entry and listing only 'name' and 'after'.
Common situations: Writing the first manual patch after switching away from buildPatchesFromDirectory() (which fills 'type' automatically); trimming a patch entry down during a refactor and dropping the key.
Related errors
- Patch '%s' has unknown patch type '%s'.
- %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
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/2b513f2af1c9acb6.
Report an issue: GitHub.