phacility/phabricator · error · Exception

Add project rule value should be a list, but is not (value i

Error message

Add 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.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.

Source

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

<?php

final class PhabricatorProjectTriggerAddProjectsRule
  extends PhabricatorProjectTriggerRule {

  const TRIGGERTYPE = 'task.projects.add';

  public function getSelectControlName() {
    return pht('Add project tags');
  }

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

  protected function assertValidRuleRecordFormat($value) {
    if (!is_array($value)) {
      throw new Exception(
        pht(
          'Add 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 add.'));
    }
  }

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

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Inspect the row: SELECT * FROM phabricator_project_trigger_rule_record WHERE type='task.projects.add' and confirm the value column holds a JSON list.
  2. 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.
  3. If the record came from an import/migration, correct the writer so it always emits an array for tokenizer-backed rules.
  4. After repair, reload the workboard or trigger edit page to confirm setRecord() no longer throws.

Example fix

// before: trigger rule record value (corrupt)
$value = 'PHID-PROJ-xyz';

// after: list of project PHIDs
$value = array('PHID-PROJ-xyz');
Defensive patterns

Strategy: type-guard

Validate before calling

// Before writing a task.projects.add rule record value:
if (!is_array($value)) {
  throw new InvalidArgumentException('add-projects value must be a list of project PHIDs');
}
PhutilTypeSpec::checkMap... // or simply:
assert(is_array($value));

Type guard

function isAddProjectsRuleValue($value) {
  return is_array($value) && !empty($value)
    && preg_match('/^PHID-PROJ-/', implode(',', $value));
}

Try / catch

try {
  $rule->setRecord($record);
} catch (Exception $ex) {
  // Corrupt stored trigger: log record ID, quarantine rule, keep board usable
  phlog($ex);
  $rule = null;
}

Prevention

When it happens

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

Common situations: 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.

Related errors


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