phacility/phabricator · error · Exception

Capability "%s" does not support public policy.

Error message

Capability "%s" does not support public policy.

What it means

policy.lock may set the value 'public' (PhabricatorPolicies::POLICY_PUBLIC) only on capabilities whose implementation opts in by overriding shouldAllowPublicPolicySetting(). Most capabilities contain user-submitted data and do not opt in, so locking them to public is rejected during config validation.

Source

Thrown at src/applications/policy/config/PolicyLockOptionType.php:40

          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));
        }
      }

      if ($policy == PhabricatorPolicies::POLICY_PUBLIC) {
        if (!$capability->shouldAllowPublicPolicySetting()) {
          throw new Exception(
            pht(
              'Capability "%s" does not support public policy.',
              $capability_key));
        }
      }
    }

    if ($policy_phids) {
      $handles = id(new PhabricatorHandleQuery())
        ->setViewer(PhabricatorUser::getOmnipotentUser())
        ->withPhids($policy_phids)
        ->execute();
      $handles = mpull($handles, null, 'getPHID');
      foreach ($value as $capability_key => $policy) {
        $handle = $handles[$policy];
        if (!$handle->isComplete()) {
          throw new Exception(
            pht(

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Use 'users' or another permitted policy value for that capability
  2. Verify the capability genuinely advertises public support before attempting to lock it to public
  3. Keep per-capability defaults from the policy UI as the source of truth for which values are acceptable

Example fix

// before: capability does not allow public policy
{"diffusion.push": "public"}

// after: use a supported policy value
{"diffusion.push": "users"}
Defensive patterns

Strategy: validation

Validate before calling

// Reject public locks on capabilities that do not allow them.
if ($policy === PhabricatorPolicies::POLICY_PUBLIC) {
  if (!$capability->shouldAllowPublicPolicySetting()) {
    // fall back to an allowed policy such as POLICY_USER
    $policy = PhabricatorPolicies::POLICY_USER;
  }
}

Type guard

function capabilityAllowsPublic(PhabricatorPolicyCapability $capability) {
  return $capability->shouldAllowPublicPolicySetting();
}

Prevention

When it happens

Trigger: The policy.lock JSON assigns the string 'public' to a capability whose PhabricatorPolicyCapability subclass returns false from shouldAllowPublicPolicySetting().

Common situations: Instance admins trying to open everything to anonymous users during initial setup; copying a public-heavy config onto capabilities that never supported public policy.

Related errors


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