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
- 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.
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
- 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.
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
- Configured datasource class "%s" must be a valid subclass of
- This contact number is already in use.
- This public key is already associated with another user or d
- Two authentication providers use the same provider key ('%s'
- Unable to upload file: this server is not configured with an
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/a902e8235cc913c1.
Report an issue: GitHub.