phacility/phabricator · error · Exception

Custom field class "%s" does not implement interface "%s".

Error message

Custom field class "%s" does not implement interface "%s".

What it means

After confirming the `object` class exists, the datasource requires it to implement PhabricatorCustomFieldInterface (the contract that supplies custom fields for objects). ReflectionClass::implementsInterface fails and this exception is thrown for any class that does not.

Source

Thrown at src/infrastructure/customfield/datasource/PhabricatorStandardSelectCustomFieldDatasource.php:32

  public function getDatasourceApplicationClass() {
    return null;
  }

  public function loadResults() {
    $viewer = $this->getViewer();

    $class = $this->getParameter('object');
    if (!class_exists($class)) {
      throw new Exception(
        pht(
          'Custom field class "%s" does not exist.',
          $class));
    }

    $reflection = new ReflectionClass($class);
    $interface = 'PhabricatorCustomFieldInterface';
    if (!$reflection->implementsInterface($interface)) {
      throw new Exception(
        pht(
          'Custom field class "%s" does not implement interface "%s".',
          $class,
          $interface));
    }

    $role = $this->getParameter('role');
    if (!strlen($role)) {
      throw new Exception(pht('No custom field role specified.'));
    }

    $object = newv($class, array());
    $field_list = PhabricatorCustomField::getObjectFields($object, $role);

    $field_key = $this->getParameter('key');
    if (!strlen($field_key)) {
      throw new Exception(pht('No custom field key specified.'));
    }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Point `object` at the domain object class that implements PhabricatorCustomFieldInterface (e.g. ManiphestTask, PhabricatorUser, PHID-hosting business objects).
  2. If it is your own class, implement PhabricatorCustomFieldInterface (getCustomFieldSpecification, getCustomFields, attachCustomFields, etc.).
  3. Verify with `is_subclass_of($class, 'PhabricatorCustomFieldInterface', true)` before wiring.

Example fix

// before
$datasource->setParameter('object', 'ManiphestTaskDAO');
// after
$datasource->setParameter('object', 'ManiphestTask');
Defensive patterns

Strategy: type-guard

Validate before calling

if (!in_array('PhabricatorCustomFieldInterface', class_implements($class), true)) {
  throw new Exception($class.' must implement PhabricatorCustomFieldInterface');
}

Type guard

function isValidCustomFieldObjectClass($class) {
  return is_string($class)
    && class_exists($class)
    && (new ReflectionClass($class))
        ->implementsInterface('PhabricatorCustomFieldInterface');
}

Prevention

When it happens

Trigger: Passing a class that exists but is a plain model/DAO class (e.g. a Maniphest task DAO or a random PhabricatorPHID class) rather than the application domain class that implements PhabricatorCustomFieldInterface.

Common situations: Pointing `object` at the wrong class in the same family (Task vs ManiphestTask, a Form vs the object); new custom object types that forgot to implement the interface; following an example that used a different install's class names.

Related errors


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