{"record":{"id":"645ae956605f57e1","repo":"phacility/phabricator","slug":"add-project-rule-value-should-be-a-list-but-is-no","errorCode":null,"errorMessage":"Add project rule value should be a list, but is not (value is \"%s\").","messagePattern":"Add project rule value should be a list, but is not \\(value is \"(.+?)\"\\)\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/project/trigger/PhabricatorProjectTriggerAddProjectsRule.php","lineNumber":18,"sourceCode":"<?php\n\nfinal class PhabricatorProjectTriggerAddProjectsRule\n  extends PhabricatorProjectTriggerRule {\n\n  const TRIGGERTYPE = 'task.projects.add';\n\n  public function getSelectControlName() {\n    return pht('Add project tags');\n  }\n\n  protected function getValueForEditorField() {\n    return $this->getDatasource()->getWireTokens($this->getValue());\n  }\n\n  protected function assertValidRuleRecordFormat($value) {\n    if (!is_array($value)) {\n      throw new Exception(\n        pht(\n          'Add project rule value should be a list, but is not '.\n          '(value is \"%s\").',\n          phutil_describe_type($value)));\n    }\n  }\n\n  protected function assertValidRuleRecordValue($value) {\n    if (!$value) {\n      throw new Exception(\n        pht(\n          'You must select at least one project tag to add.'));\n    }\n  }\n\n  protected function newDropTransactions($object, $value) {\n    $project_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;\n","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/project/trigger/PhabricatorProjectTriggerAddProjectsRule.php#L1-L36","documentation":"Thrown by assertValidRuleRecordFormat() when the stored value of a 'task.projects.add' (Add Projects) trigger rule is not a PHP array. The check runs in PhabricatorProjectTriggerRule::setRecord(), which executes every time a trigger rule record is loaded from the database (workboard rendering, trigger editing, card drop). It means the JSON in PhabricatorProjectTriggerRuleRecord.value is corrupt or was written with the wrong shape.","triggerScenarios":"Loading or saving any trigger whose rule of type 'task.projects.add' has a non-list value, e.g. the value column contains a bare PHID string instead of a JSON array of PHIDs. Reproduce with: a trigger record where phabricator_project_trigger_rule_record.value = \"PHID-PROJ-xyz\" instead of [\"PHID-PROJ-xyz\"], then open a workboard that uses the trigger.","commonSituations":"Hand-edited database rows, a migration or import script that wrote scalar values, an older Phorge/Phabricator version that stored the value differently, or a custom code path calling setRecord() with a hand-built record object.","solutions":["Inspect the row: SELECT * FROM phabricator_project_trigger_rule_record WHERE type='task.projects.add' and confirm the value column holds a JSON list.","Fix the stored value to a JSON array of project PHIDs, e.g. [\"PHID-PROJ-xyz\"], via the trigger editor (preferred) or a storage repair script.","If the record came from an import/migration, correct the writer so it always emits an array for tokenizer-backed rules.","After repair, reload the workboard or trigger edit page to confirm setRecord() no longer throws."],"exampleFix":"// before: trigger rule record value (corrupt)\n$value = 'PHID-PROJ-xyz';\n\n// after: list of project PHIDs\n$value = array('PHID-PROJ-xyz');","handlingStrategy":"type-guard","validationCode":"// Before writing a task.projects.add rule record value:\nif (!is_array($value)) {\n  throw new InvalidArgumentException('add-projects value must be a list of project PHIDs');\n}\nPhutilTypeSpec::checkMap... // or simply:\nassert(is_array($value));","typeGuard":"function isAddProjectsRuleValue($value) {\n  return is_array($value) && !empty($value)\n    && preg_match('/^PHID-PROJ-/', implode(',', $value));\n}","tryCatchPattern":"try {\n  $rule->setRecord($record);\n} catch (Exception $ex) {\n  // Corrupt stored trigger: log record ID, quarantine rule, keep board usable\n  phlog($ex);\n  $rule = null;\n}","preventionTips":["Always create trigger records through the trigger editor or the standard editor APIs so value shapes match the rule type.","Validate value shape (is_array for list rules) before persisting PhabricatorProjectTriggerRuleRecord rows.","Back up and dry-run any script that bulk-edits phabricator_project_trigger_rule_record."],"tags":["php","phabricator","project-triggers","workboard","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"}