{"record":{"id":"c4ccbd1c84952a04","repo":"phacility/phabricator","slug":"field-s-expects-a-string-value-but-received-a","errorCode":null,"errorMessage":"Field \"%s\" expects a string value, but received a value of type \"%s\".","messagePattern":"Field \"(.+?)\" expects a string value, but received a value of type \"(.+?)\"\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/differential/field/DifferentialCommitMessageField.php","lineNumber":158,"sourceCode":"        $token = $handle->getCommandLineObjectName();\n      }\n\n      $suffix = idx($suffixes, $phid);\n      $token = $token.$suffix;\n\n      $out[] = $token;\n    }\n\n    return implode(', ', $out);\n  }\n\n  protected function readStringFieldValueFromConduit($value) {\n    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)));","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/differential/field/DifferentialCommitMessageField.php#L140-L176","documentation":"Custom commit-message fields validate their Conduit input through DifferentialCommitMessageField::readStringFieldValueFromConduit(). When a field declared to hold a single string receives a non-null value that is not a PHP string (int, float, bool, array), it throws, naming the field key and the received type. This is strict boundary type validation for Conduit methods like 'differential.revision.edit' and commit-message parsing APIs that write string fields (e.g., custom prose fields).","triggerScenarios":"Passing an integer (e.g., 123 instead of '123') or an array (e.g., array('a')) as a string field value in the 'fields' map of a Conduit request; JSON clients that infer types (Python dict with int, JS number); omitting quotes around numeric strings in hand-built JSON payloads.","commonSituations":"Custom string fields registered via PhabricatorCustomField extensions; third-party tooling posting typed JSON where older versions tolerated loose types; migration scripts that re-encode values and lose string typing.","solutions":["Send the value as a JSON string (\"123\" instead of 123) for the field key named in the message","Cast values to string client-side before building the Conduit request (e.g., str(val) in Python, String(val) in JS)","If you own the field subclass, override readFieldValueFromConduit() to coerce acceptable types instead of inheriting the strict check","Log the full fields map you are sending to identify which key carries the wrong type"],"exampleFix":"// before (Python, Conduit 'differential.revision.edit')\nparams = {'objectPHID': rev_phid, 'transactions': [{\n  'type': 'revision.setfield',\n  'value': {'field': 'custom:myfield', 'value': 42},\n}]}\n\n// after\nparams = {'objectPHID': rev_phid, 'transactions': [{\n  'type': 'revision.setfield',\n  'value': {'field': 'custom:myfield', 'value': '42'},\n}]}","handlingStrategy":"type-guard","validationCode":"// PHP client: coerce every string-field value before the Conduit call\nforeach ($fields as $k => $v) {\n  if ($v !== null && !is_string($v)) {\n    $fields[$k] = (string)$v;\n  }\n}","typeGuard":"function isValidStringFieldValue($value) {\n  return $value === null || is_string($value);\n}","tryCatchPattern":"try {\n  $field->readFieldValueFromConduit($value);\n} catch (Exception $ex) {\n  // The message names the field key and received type;\n  // coerce that key to a string and retry once.\n}","preventionTips":["Always send string fields as JSON strings, including digits and booleans","Centralize Conduit payload building in one helper that enforces per-field types","Check the field key in the exception text to locate the offending entry quickly"],"tags":["phabricator","differential","conduit","custom-field","type-validation","commit-message"],"backgroundTag":"invalid-argument-type","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}