{"record":{"id":"a902e8235cc913c1","repo":"phacility/phabricator","slug":"both-s-and-s-define-a-custom-field-with-fiel","errorCode":null,"errorMessage":"Both '%s' and '%s' define a custom field with field key '%s'. Field keys must be unique.","messagePattern":"Both '(.+?)' and '(.+?)' define a custom field with field key '(.+?)'\\. Field keys must be unique\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/customfield/field/PhabricatorCustomField.php","lineNumber":141,"sourceCode":"   * @task apps\n   */\n  public static function buildFieldList(\n    $base_class,\n    array $spec,\n    $object,\n    array $options = array()) {\n\n    $field_objects = id(new PhutilClassMapQuery())\n      ->setAncestorClass($base_class)\n      ->execute();\n\n    $fields = array();\n    foreach ($field_objects as $field_object) {\n      $field_object = clone $field_object;\n      foreach ($field_object->createFields($object) as $field) {\n        $key = $field->getFieldKey();\n        if (isset($fields[$key])) {\n          throw new Exception(\n            pht(\n              \"Both '%s' and '%s' define a custom field with \".\n              \"field key '%s'. Field keys must be unique.\",\n              get_class($fields[$key]),\n              get_class($field),\n              $key));\n        }\n        $fields[$key] = $field;\n      }\n    }\n\n    foreach ($fields as $key => $field) {\n      if (!$field->isFieldEnabled()) {\n        unset($fields[$key]);\n      }\n    }\n\n    $fields = array_select_keys($fields, array_keys($spec)) + $fields;","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/customfield/field/PhabricatorCustomField.php#L123-L159","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename one field's key: in a custom field class override getFieldKey() to return a unique namespaced key (e.g. 'mycompany:task:division').","If the clash is with an inherited key, make the subclass override getFieldKey() (and getField_name) rather than reusing the parent's.","Disable one of the two conflicting extensions, or configure the field out via the custom-field config, until keys are unique.","After fixing, verify by loading the affected object's edit or view page, which triggers field list construction."],"exampleFix":"// before: subclass inherits the parent's field key\nclass MyCompanyTaskField extends ManiphestTaskCoreField {}\n// after\n class MyCompanyTaskField extends ManiphestTaskCoreField {\n  public function getFieldKey() {\n    return 'mycompany:task:division';\n  }\n}","handlingStrategy":"validation","validationCode":"// Detect duplicate keys across all field classes before install:\n$seen = array();\nforeach ($field_objects as $field_object) {\n  foreach ($field_object->createFields($object) as $field) {\n    $key = $field->getFieldKey();\n    if (isset($seen[$key])) {\n      throw new Exception(\n        'Duplicate field key \"'.$key.'\" defined by '.\n        get_class($seen[$key]).' and '.get_class($field));\n    }\n    $seen[$key] = $field;\n  }\n}","typeGuard":"function hasUniqueFieldKeys(array $fields) {\n  $keys = array();\n  foreach ($fields as $field) {\n    $keys[$field->getFieldKey()] = true;\n  }\n  return count($keys) === count($fields);\n}","tryCatchPattern":null,"preventionTips":["Namespace custom field keys by vendor/app ('mycompany:task:...') so third-party extensions cannot collide with yours.","Always override getFieldKey() when subclassing an existing field class — inherited keys collide with the parent's instances.","Run a smoke test that loads getObjectFields() for each customized object type after installing or updating any field extension."],"tags":["php","phabricator","custom-fields","configuration","extensions","duplicate-key"],"backgroundTag":"duplicate-custom-field-key","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}