phacility/phabricator · error · Exception
Capability "%s" does not exist.
Error message
Capability "%s" does not exist.
What it means
policy.lock is a JSON config option that force-locks object policies per capability. PolicyLockOptionType::validateOption() expands every PhabricatorPolicyCapability subclass into a key map and rejects any key in the JSON that is not a registered capability key. The whole config write is refused, keeping the lock set consistent with installed capability classes.
Source
Thrown at src/applications/policy/config/PolicyLockOptionType.php:16
<?php
final class PolicyLockOptionType
extends PhabricatorConfigJSONOptionType {
public function validateOption(PhabricatorConfigOption $option, $value) {
$capabilities = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorPolicyCapability')
->setUniqueMethod('getCapabilityKey')
->execute();
$policy_phids = array();
foreach ($value as $capability_key => $policy) {
$capability = idx($capabilities, $capability_key);
if (!$capability) {
throw new Exception(
pht(
'Capability "%s" does not exist.',
$capability_key));
}
if (phid_get_type($policy) !=
PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) {
$policy_phids[$policy] = $policy;
} else {
try {
$policy_object = PhabricatorPolicyQuery::getGlobalPolicy($policy);
// this exception is not helpful here as its about global policy;
// throw a better exception
} catch (Exception $ex) {
throw new Exception(
pht(
'Capability "%s" has invalid policy "%s".',
$capability_key,
$policy));View on GitHub (pinned to 5720a38cfe)
Solutions
- Remove or correct the unknown capability key in the policy.lock configuration
- Enumerate valid keys by listing PhabricatorPolicyCapability subclasses (or the policy UI pickers) and use exactly those strings
- Re-validate saved policy.lock values after upgrades, since retired keys only surface on the next save
Example fix
// before: unknown capability key rejects the whole config
{"maniphest.priorities": "admin"}
// after: use a capability key that actually exists
{"diffusion.push": "admin"} Defensive patterns
Strategy: validation
Validate before calling
// Validate policy.lock keys before saving.
$capabilities = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorPolicyCapability')
->setUniqueMethod('getCapabilityKey')
->execute();
foreach ($value as $capability_key => $_) {
if (empty($capabilities[$capability_key])) {
throw new Exception(pht('Unknown capability key: %s', $capability_key));
}
} Type guard
function isKnownPolicyCapability($key) {
static $keys;
if ($keys === null) {
$keys = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorPolicyCapability')
->setUniqueMethod('getCapabilityKey')
->execute();
}
return isset($keys[$key]);
} Prevention
- Lint policy.lock keys against installed capabilities in CI for config-as-code setups
- Re-validate lock configs after every Phabricator upgrade or extension change
- Never hand-type capability keys; copy them from the policy UI or class constants
When it happens
Trigger: Saving policy.lock containing a capability key no PhabricatorPolicyCapability subclass provides: a typo, a key removed by an upgrade, or a key defined by an extension that is no longer installed.
Common situations: Copy-pasting config between instances with different extensions installed; upgrading Phabricator where a capability was renamed or retired; hand-editing the policy.lock JSON.
Related errors
- Capability "%s" has invalid policy "%s".
- Capability "%s" does not support public policy.
- The following regex is malformed and cannot be used: %s
- You can not accept this commit because you are the commit au
- Book configuration '%s' has name '%s', but book names must i
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/a95e48cb33986ba4.
Report an issue: GitHub.