{"record":{"id":"0fe9eb79ffbb686d","repo":"phacility/phabricator","slug":"field-s-expects-a-list-of-strings-but-received","errorCode":null,"errorMessage":"Field \"%s\" expects a list of strings, but received a value of type \"%s\".","messagePattern":"Field \"(.+?)\" expects a list of strings, but received a value of type \"(.+?)\"\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/differential/field/DifferentialCommitMessageField.php","lineNumber":171,"sourceCode":"    if ($value === null) {\n      return $value;\n    }\n\n    if (!is_string($value)) {\n      throw new Exception(\n        pht(\n          'Field \"%s\" expects a string value, but received a value of type '.\n          '\"%s\".',\n          $this->getCommitMessageFieldKey(),\n          gettype($value)));\n    }\n\n    return $value;\n  }\n\n  protected function readStringListFieldValueFromConduit($value) {\n    if (!is_array($value)) {\n      throw new Exception(\n        pht(\n          'Field \"%s\" expects a list of strings, but received a value of type '.\n          '\"%s\".',\n          $this->getCommitMessageFieldKey(),\n          gettype($value)));\n    }\n\n    return $value;\n  }\n\n  protected function isCustomFieldEnabled($key) {\n    $field_list = PhabricatorCustomField::getObjectFields(\n      new DifferentialRevision(),\n      DifferentialCustomField::ROLE_DEFAULT);\n\n    $fields = $field_list->getFields();\n    return isset($fields[$key]);\n  }","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/differential/field/DifferentialCommitMessageField.php#L153-L189","documentation":"DifferentialCommitMessageField::readStringListFieldValueFromConduit() validates that list-type commit-message fields receive a PHP array; any non-array value (including null, which the single-string variant tolerates) throws with the field key and received type. It guards fields whose value is a list of strings (e.g., reviewers-style custom fields) on Conduit write paths such as 'differential.revision.edit'.","triggerScenarios":"Passing a single string where the field expects a list (e.g., 'alice' instead of array('alice')); passing null for a list field (null is rejected here, unlike the string variant); passing an int or object from a loosely typed client payload.","commonSituations":"Clients upgrading from single-value to list-value custom fields and still sending scalars; JSON payloads where the list key is omitted or replaced by a scalar; automation sharing field templates between string and list fields.","solutions":["Send a JSON array of strings for the field key named in the message, even for a single value ([\"alice\"] not \"alice\")","Never send null for a list field; send an empty array [] to clear it","Add a client-side check that the value is an array before issuing the Conduit call","If the field should accept scalars, override readFieldValueFromConduit() in the field subclass to wrap scalars into a one-element array"],"exampleFix":"// before\nconduit.call('differential.revision.edit', {\n  transactions: [{type: 'revision.setfield',\n    value: {field: 'custom:reviewers-ext', value: 'alice'}}]\n});\n\n// after\nconduit.call('differential.revision.edit', {\n  transactions: [{type: 'revision.setfield',\n    value: {field: 'custom:reviewers-ext', value: ['alice']}}]\n});","handlingStrategy":"type-guard","validationCode":"// PHP client: force list-of-strings shape before the Conduit call\nforeach ($list_fields as $k) {\n  $v = $fields[$k];\n  if ($v === null) {\n    $fields[$k] = array();          // null is rejected; use [] to clear\n  } elseif (is_string($v)) {\n    $fields[$k] = array($v);        // wrap single values\n  } elseif (is_array($v)) {\n    $fields[$k] = array_map('strval', $v);\n  }\n}","typeGuard":"function isValidStringListFieldValue($value) {\n  return is_array($value)\n    && array_reduce($value, function ($ok, $v) { return $ok && is_string($v); }, true);\n}","tryCatchPattern":"try {\n  $field->readFieldValueFromConduit($value);\n} catch (Exception $ex) {\n  // Wrap scalars / replace null with [] for the named field, then retry.\n}","preventionTips":["Send JSON arrays for list fields even with a single element","Send [] rather than null to clear a list field","Keep a client-side schema of which custom fields are strings vs lists and validate against it"],"tags":["phabricator","differential","conduit","custom-field","type-validation","list"],"backgroundTag":"invalid-argument-type","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}