phacility/phabricator · error · Exception

Patch '%s' references nonexistent dependency, '%s'. Patches

Error message

Patch '%s' references nonexistent dependency, '%s'. Patches may only depend on patches which actually exist.

What it means

After all lists are loaded, every entry in a patch's 'after' array is looked up in the global spec map. Dependencies must reference patches that actually exist (in the same or another namespace), because Phabricator applies patches in dependency order and a dangling reference makes the order undefined. Bare dependency names are auto-prefixed with the current namespace before lookup, so a bare name of a patch from another namespace will not resolve.

Source

Thrown at src/infrastructure/storage/patch/PhabricatorSQLPatchList.php:223

          case 'sql':
          case 'php':
            break;
          default:
            throw new Exception(
              pht(
                "Patch '%s' has unknown patch type '%s'.",
                "{$namespace}:{$key}",
                $type));
        }

        $specs[$full_key] = $patch;
      }
    }

    foreach ($specs as $key => $patch) {
      foreach ($patch['after'] as $after) {
        if (empty($specs[$after])) {
          throw new Exception(
            pht(
              "Patch '%s' references nonexistent dependency, '%s'. ".
              "Patches may only depend on patches which actually exist.",
              $key,
              $after));
        }

        $patch_phase = $patch['phase'];
        $after_phase = $specs[$after]['phase'];

        if ($patch_phase !== $after_phase) {
          throw new Exception(
            pht(
              'Storage patch "%s" executes in phase "%s", but depends on '.
              'patch "%s" which is in a different phase ("%s"). Patches '.
              'may not have dependencies across phases.',
              $key,
              $patch_phase,

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Check the dependency name character-by-character against the real patch key.
  2. If the dependency lives in another namespace, spell it fully as 'namespace:patchname'.
  3. If the dependency no longer exists (renamed/removed), update the 'after' entry to its replacement or drop it.
  4. Re-run 'bin/storage status' to confirm all references resolve.

Example fix

// before (inside application namespace 'myapp')
'after' => array(
  '20171231.core.thing.sql',   // actually a phabricator patch -> not found
),

// after
'after' => array(
  'phabricator:20171231.core.thing.sql',
),
Defensive patterns

Strategy: validation

Validate before calling

// Verify every dependency resolves in the global patch map:
$specs = PhabricatorSQLPatchList::buildAllPatches(); // itself throws on dangling refs
foreach ((new MyApplicationPatchList())->getPatches() as $key => $patch) {
  foreach (idx($patch, 'after', array()) as $after) {
    if (strpos($after, ':') === false) {
      $after = $list->getNamespace().':'.$after; // mirror the loader's expansion
    }
    if (empty($specs[$after])) {
      throw new Exception("Patch '{$key}' depends on missing patch '{$after}'");
    }
  }
}

Prevention

When it happens

Trigger: An 'after' entry is a typo ('20170101.widget.sq1'), references a patch that was renamed or removed, or names a patch from a different namespace without the 'namespace:' prefix (the loader prepends your own namespace, so it misses).

Common situations: Typos in dependency keys; depending on a patch that exists only in a newer/older Phabricator version than you run; depending on an extension's patch that is not installed; renaming a patch without updating its dependents.

Related errors


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