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
- Point `object` at the domain object class that implements PhabricatorCustomFieldInterface (e.g. ManiphestTask, PhabricatorUser, PHID-hosting business objects).
- If it is your own class, implement PhabricatorCustomFieldInterface (getCustomFieldSpecification, getCustomFields, attachCustomFields, etc.).
- 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
- Point `object` at the application domain class (ManiphestTask, PhabricatorUser), not DAOs or helpers.
- For custom object types, implement PhabricatorCustomFieldInterface early and cover it with a smoke test that builds the field list.
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
- Custom field class "%s" does not exist.
- No custom field role specified.
- No custom field key specified.
- No field with field key "%s" exists for objects of class "%s
- Field "%s" is not a standard select field, nor a proxy of a
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/649f8ebc24aec9cc.
Report an issue: GitHub.