{"record":{"id":"7436793d72721de6","repo":"phacility/phabricator","slug":"remove-project-rule-value-should-be-a-list-but-is","errorCode":null,"errorMessage":"Remove project rule value should be a list, but is not (value is \"%s\").","messagePattern":"Remove project rule value should be a list, but is not \\(value is \"(.+?)\"\\)\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/project/trigger/PhabricatorProjectTriggerRemoveProjectsRule.php","lineNumber":18,"sourceCode":"<?php\n\nfinal class PhabricatorProjectTriggerRemoveProjectsRule\n  extends PhabricatorProjectTriggerRule {\n\n  const TRIGGERTYPE = 'task.projects.remove';\n\n  public function getSelectControlname() {\n    return pht('Remove 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          'Remove 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 remove.'));\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/PhabricatorProjectTriggerRemoveProjectsRule.php#L1-L36","documentation":"Thrown by assertValidRuleRecordFormat() when the stored value of a 'task.projects.remove' (Remove Projects) trigger rule is not an array. The check runs in PhabricatorProjectTriggerRule::setRecord() on every load of the rule record; the rule expects a JSON list of project PHIDs produced by the tokenizer.","triggerScenarios":"A task.projects.remove rule whose value column contains a scalar (single PHID string, null) instead of an array. Opening a workboard with that trigger, editing the trigger, or dropping a card onto its column triggers the exception in setRecord().","commonSituations":"Hand-edited database value; import/migration wrote one PHID instead of a list; older or custom writer used the wrong shape.","solutions":["Query the record: SELECT * FROM phabricator_project_trigger_rule_record WHERE type='task.projects.remove'; and confirm the value is a JSON list.","Rewrite the value to an array of project PHIDs, e.g. [\"PHID-PROJ-xyz\"], via the editor or a repair script.","Fix the import/migration path to always emit arrays for project-list rules.","Reload the workboard/trigger to confirm."],"exampleFix":"// before\n$value = 'PHID-PROJ-xyz';\n\n// after\n$value = array('PHID-PROJ-xyz');","handlingStrategy":"type-guard","validationCode":"if (!is_array($value)) {\n  throw new InvalidArgumentException(\n    'remove-projects value must be a list of project PHIDs');\n}","typeGuard":"function isRemoveProjectsRuleValue($value) {\n  return is_array($value);\n}","tryCatchPattern":"try {\n  $rule->setRecord($record);\n} catch (Exception $ex) {\n  phlog('Corrupt task.projects.remove record '.$record->getID());\n  continue;\n}","preventionTips":["Use the tokenizer output shape (array) for all project-list rules.","Audit migration scripts: task.projects.remove and task.projects.add share a shape.","Add integrity checks to re-imports of trigger tables."],"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"}