phacility/phabricator · error · HeraldInvalidConditionException

Expected condition value to be an array.

Error message

Expected condition value to be an array.

What it means

While evaluating a Herald rule, the CONDITION_INCLUDE_ALL branch ('include all of') requires both the field value (checked first, 'Object produced non-array value!') and the stored condition value to be arrays. Here the field produced an array but the condition's saved value is a scalar, so the adapter throws HeraldInvalidConditionException. The Herald engine catches it, marks the rule as errored in the transcript, and the rule does not apply.

Source

Thrown at src/applications/herald/adapter/HeraldAdapter.php:495

          throw new HeraldInvalidConditionException(
            pht('Expected condition value to be an array.'));
        }
        $condition_value = array_fuse($condition_value);
        return isset($condition_value[$field_value]);
      case self::CONDITION_IS_NOT_ANY:
        if (!is_array($condition_value)) {
          throw new HeraldInvalidConditionException(
            pht('Expected condition value to be an array.'));
        }
        $condition_value = array_fuse($condition_value);
        return !isset($condition_value[$field_value]);
      case self::CONDITION_INCLUDE_ALL:
        if (!is_array($field_value)) {
          throw new HeraldInvalidConditionException(
            pht('Object produced non-array value!'));
        }
        if (!is_array($condition_value)) {
          throw new HeraldInvalidConditionException(
            pht('Expected condition value to be an array.'));
        }

        $have = array_select_keys(array_fuse($field_value), $condition_value);
        return (count($have) == count($condition_value));
      case self::CONDITION_INCLUDE_ANY:
        return (bool)array_select_keys(
          array_fuse($field_value),
          $condition_value);
      case self::CONDITION_INCLUDE_NONE:
        return !array_select_keys(
          array_fuse($field_value),
          $condition_value);
      case self::CONDITION_EXISTS:
      case self::CONDITION_IS_TRUE:
        return (bool)$field_value;
      case self::CONDITION_NOT_EXISTS:
      case self::CONDITION_IS_FALSE:

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Re-save the rule in the Herald web UI: open the rule, the condition editor will normalize the value into a list, then save.
  2. If editing via API, pass the value as an array, e.g. array('PHID-PROJ-...') instead of 'PHID-PROJ-...'.
  3. For many broken rules, fix the herald_condition.value column (or re-save each rule) so the value is a JSON/PHP array.

Example fix

// before (herald.rule.edit via Conduit)
{"value": "PHID-PROJ-aaaa"}

// after
{"value": ["PHID-PROJ-aaaa"]}
Defensive patterns

Strategy: validation

Validate before calling

// When writing rules via API, pre-validate multi-value conditions:
$multi = array(
  HeraldAdapter::CONDITION_INCLUDE_ALL,
  HeraldAdapter::CONDITION_IS_ANY,
  HeraldAdapter::CONDITION_IS_NOT_ANY,
);
if (in_array($condition_type, $multi, true) && !is_array($value)) {
  $value = array($value); // normalize to the array shape the adapter requires
}

Type guard

function isHeraldMultiValueCondition($type) {
  return in_array($type, array(
    HeraldAdapter::CONDITION_INCLUDE_ALL,
    HeraldAdapter::CONDITION_IS_ANY,
    HeraldAdapter::CONDITION_IS_NOT_ANY,
  ), true);
}

Try / catch

try {
  $adapter->doesConditionMatch($rule, $condition, $field_value);
} catch (HeraldInvalidConditionException $ex) {
  // engine-level handling: rule is skipped and marked errored;
  // in custom scripts, log the rule monogram and skip the rule
}

Prevention

When it happens

Trigger: A rule with an 'include all of' condition (e.g. 'include all of these projects/reviewers') whose stored value is a plain string/PHID instead of a list — typically written via the Conduit API, a rule import, or corrupted storage rather than the web editor (the UI saves arrays and willSaveCondition validates).

Common situations: Rules created or edited via herald.rule.edit Conduit with value passed as a scalar; migrations between instances; batch rule generation scripts that did not wrap values in an array.

Related errors


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