{"record":{"id":"7fcb7826d7a577c4","repo":"phacility/phabricator","slug":"status-rule-value-should-be-a-string-but-is-not-7fcb78","errorCode":null,"errorMessage":"Status rule value should be a string, but is not (value is \"%s\").","messagePattern":"Status rule value should be a string, but is not \\(value is \"(.+?)\"\\)\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/project/trigger/PhabricatorProjectTriggerPlaySoundRule.php","lineNumber":14,"sourceCode":"<?php\n\nfinal class PhabricatorProjectTriggerPlaySoundRule\n  extends PhabricatorProjectTriggerRule {\n\n  const TRIGGERTYPE = 'sound';\n\n  public function getSelectControlName() {\n    return pht('Play sound');\n  }\n\n  protected function assertValidRuleRecordFormat($value) {\n    if (!is_string($value)) {\n      throw new Exception(\n        pht(\n          'Status rule value should be a string, but is not (value is \"%s\").',\n          phutil_describe_type($value)));\n    }\n  }\n\n  protected function assertValidRuleRecordValue($value) {\n    $map = self::getSoundMap();\n    if (!isset($map[$value])) {\n      throw new Exception(\n        pht(\n          'Sound (\"%s\") is not a valid sound.',\n          $value));\n    }\n  }\n\n  protected function newDropTransactions($object, $value) {\n    return array();","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/project/trigger/PhabricatorProjectTriggerPlaySoundRule.php#L1-L32","documentation":"Thrown by assertValidRuleRecordFormat() when the stored value of a 'sound' (Play Sound) trigger rule is not a string. It runs in PhabricatorProjectTriggerRule::setRecord() on every rule load. Note the message text says 'Status rule value' — an upstream copy-paste from the status rule — but this validates the sound rule.","triggerScenarios":"A 'sound' rule whose value column holds a non-string (array, int, null) instead of a sound key string. Rendering a workboard that uses the trigger, editing the trigger, or dropping a card hits setRecord() and throws.","commonSituations":"Hand-edited DB value; import script wrote the sound as a list; corrupt JSON after a partial migration.","solutions":["Find the row: SELECT * FROM phabricator_project_trigger_rule_record WHERE type='sound'; and check the value type.","Rewrite the value to a string sound key accepted by PhabricatorProjectTriggerPlaySoundRule::getSoundMap(), e.g. via the trigger editor.","Fix the writer/importer that produced the non-string value.","Verify the workboard loads afterwards."],"exampleFix":"// before\n$value = array('bing');\n\n// after (a key from getSoundMap())\n$value = 'bing';","handlingStrategy":"type-guard","validationCode":"if (!is_string($value)) {\n  throw new InvalidArgumentException('sound value must be a string key');\n}","typeGuard":"function isSoundRuleValue($value) {\n  return is_string($value) && $value !== '';\n}","tryCatchPattern":"try {\n  $rule->setRecord($record);\n} catch (Exception $ex) {\n  // note: upstream message says 'Status rule value' for sound rules\n  phlog('Corrupt sound trigger record '.$record->getID());\n  continue;\n}","preventionTips":["Sound rules store one scalar key exactly like status rules.","Do not guess the copy-pasted message wording when handling; match on the rule type instead.","Validate value types in any bulk trigger-editing tool."],"tags":["php","phabricator","project-triggers","sound-rule","data-corruption"],"backgroundTag":"stored-config-validation-failed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}