phacility/phabricator · error · Exception

Custom field class "%s" does not exist.

Error message

Custom field class "%s" does not exist.

What it means

PhabricatorStandardSelectCustomFieldDatasource::loadResults() reads the `object` parameter (a class name), expects it to name an existing class, and throws immediately when `class_exists($class)` is false. The parameter is supplied by whoever wires up the typeahead datasource, so the error indicates a wiring or naming mistake, not user input.

Source

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

  public function getBrowseTitle() {
    return pht('Browse Values');
  }

  public function getPlaceholderText() {
    return pht('Type a field value...');
  }

  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.'));

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Set the `object` parameter to a fully qualified, currently existing class name (verify with a quick `class_exists()` check or `bin/dev lookup class`).
  2. If the class came from an extension, reinstall/enable that extension.
  3. Regenerate the datasource/function wiring after renaming a field class so the stored parameter matches.

Example fix

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

Strategy: validation

Validate before calling

$class = $datasource->getParameter('object');
if (!class_exists($class)) {
  throw new Exception('object parameter must be an existing class: '.$class);
}

Type guard

function isValidCustomFieldObjectClass($class) {
  return is_string($class)
    && class_exists($class)
    && is_subclass_of($class, 'PhabricatorCustomFieldInterface', true);
}

Prevention

When it happens

Trigger: Instantiating the datasource (or registering a typeahead function) with an `object` parameter that names a missing class — a typo, a class renamed between versions, or an extension that was disabled after the datasource config was written.

Common situations: Typeahead function definitions referencing custom field classes from an uninstalled extension; copying datasource wiring between installs where class names differ; case mismatches in namespaced class names.

Related errors


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