phacility/phabricator · error · Exception

Both '%s' and '%s' define a custom field with field key '%s'

Error message

Both '%s' and '%s' define a custom field with field key '%s'. Field keys must be unique.

What it means

When PhabricatorCustomField builds the field list for an object (getObjectFields → buildFieldList), it merges fields from every class in the PhabricatorCustomField class map. Field keys must be globally unique per object; if two field classes emit the same getFieldKey(), the second one throws naming both offending classes and the duplicated key.

Source

Thrown at src/infrastructure/customfield/field/PhabricatorCustomField.php:141

   * @task apps
   */
  public static function buildFieldList(
    $base_class,
    array $spec,
    $object,
    array $options = array()) {

    $field_objects = id(new PhutilClassMapQuery())
      ->setAncestorClass($base_class)
      ->execute();

    $fields = array();
    foreach ($field_objects as $field_object) {
      $field_object = clone $field_object;
      foreach ($field_object->createFields($object) as $field) {
        $key = $field->getFieldKey();
        if (isset($fields[$key])) {
          throw new Exception(
            pht(
              "Both '%s' and '%s' define a custom field with ".
              "field key '%s'. Field keys must be unique.",
              get_class($fields[$key]),
              get_class($field),
              $key));
        }
        $fields[$key] = $field;
      }
    }

    foreach ($fields as $key => $field) {
      if (!$field->isFieldEnabled()) {
        unset($fields[$key]);
      }
    }

    $fields = array_select_keys($fields, array_keys($spec)) + $fields;

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Rename one field's key: in a custom field class override getFieldKey() to return a unique namespaced key (e.g. 'mycompany:task:division').
  2. If the clash is with an inherited key, make the subclass override getFieldKey() (and getField_name) rather than reusing the parent's.
  3. Disable one of the two conflicting extensions, or configure the field out via the custom-field config, until keys are unique.
  4. After fixing, verify by loading the affected object's edit or view page, which triggers field list construction.

Example fix

// before: subclass inherits the parent's field key
class MyCompanyTaskField extends ManiphestTaskCoreField {}
// after
 class MyCompanyTaskField extends ManiphestTaskCoreField {
  public function getFieldKey() {
    return 'mycompany:task:division';
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Detect duplicate keys across all field classes before install:
$seen = array();
foreach ($field_objects as $field_object) {
  foreach ($field_object->createFields($object) as $field) {
    $key = $field->getFieldKey();
    if (isset($seen[$key])) {
      throw new Exception(
        'Duplicate field key "'.$key.'" defined by '.
        get_class($seen[$key]).' and '.get_class($field));
    }
    $seen[$key] = $field;
  }
}

Type guard

function hasUniqueFieldKeys(array $fields) {
  $keys = array();
  foreach ($fields as $field) {
    $keys[$field->getFieldKey()] = true;
  }
  return count($keys) === count($fields);
}

Prevention

When it happens

Trigger: Two extensions (or an extension plus core) both define a field with the same key — e.g. both return 'std:company:division' from createFields(); or a custom field subclass forgets to override getFieldKey() and inherits its parent's key, colliding with the parent's own instances.

Common situations: Installing a third-party custom field extension whose keys clash with locally written fields; copying a core field class to customize it without changing its field key; upgrading an extension that introduces a key already defined locally.

Related errors


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