phacility/phabricator · error · Exception

Remove project rule value should be a list, but is not (valu

Error message

Remove project rule value should be a list, but is not (value is "%s").

What it means

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.

Source

Thrown at src/applications/project/trigger/PhabricatorProjectTriggerRemoveProjectsRule.php:18

<?php

final class PhabricatorProjectTriggerRemoveProjectsRule
  extends PhabricatorProjectTriggerRule {

  const TRIGGERTYPE = 'task.projects.remove';

  public function getSelectControlname() {
    return pht('Remove project tags');
  }

  protected function getValueForEditorField() {
    return $this->getDatasource()->getWireTokens($this->getValue());
  }

  protected function assertValidRuleRecordFormat($value) {
    if (!is_array($value)) {
      throw new Exception(
        pht(
          'Remove project rule value should be a list, but is not '.
          '(value is "%s").',
          phutil_describe_type($value)));
    }
  }

  protected function assertValidRuleRecordValue($value) {
    if (!$value) {
      throw new Exception(
        pht(
          'You must select at least one project tag to remove.'));
    }
  }

  protected function newDropTransactions($object, $value) {
    $project_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Query the record: SELECT * FROM phabricator_project_trigger_rule_record WHERE type='task.projects.remove'; and confirm the value is a JSON list.
  2. Rewrite the value to an array of project PHIDs, e.g. ["PHID-PROJ-xyz"], via the editor or a repair script.
  3. Fix the import/migration path to always emit arrays for project-list rules.
  4. Reload the workboard/trigger to confirm.

Example fix

// before
$value = 'PHID-PROJ-xyz';

// after
$value = array('PHID-PROJ-xyz');
Defensive patterns

Strategy: type-guard

Validate before calling

if (!is_array($value)) {
  throw new InvalidArgumentException(
    'remove-projects value must be a list of project PHIDs');
}

Type guard

function isRemoveProjectsRuleValue($value) {
  return is_array($value);
}

Try / catch

try {
  $rule->setRecord($record);
} catch (Exception $ex) {
  phlog('Corrupt task.projects.remove record '.$record->getID());
  continue;
}

Prevention

When it happens

Trigger: 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().

Common situations: Hand-edited database value; import/migration wrote one PHID instead of a list; older or custom writer used the wrong shape.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/7436793d72721de6. Report an issue: GitHub.