phacility/phabricator · error · HeraldInvalidConditionException

Regular expression pair is not a pair!

Error message

Regular expression pair is not a pair!

What it means

For CONDITION_REGEXP_PAIR, the condition value decoded as JSON but count($regexp_pair) != 2 — the JSON is valid but not a two-element array. The adapter needs exactly one key regexp and one value regexp, so any other length is rejected with HeraldInvalidConditionException before matching begins.

Source

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

          if ($result) {
            return $result_if_match;
          }
        }
        return !$result_if_match;
      case self::CONDITION_REGEXP_PAIR:
        // Match a JSON-encoded pair of regular expressions against a
        // dictionary. The first regexp must match the dictionary key, and the
        // second regexp must match the dictionary value. If any key/value pair
        // in the dictionary matches both regexps, the condition is satisfied.
        $regexp_pair = null;
        try {
          $regexp_pair = phutil_json_decode($condition_value);
        } catch (PhutilJSONParserException $ex) {
          throw new HeraldInvalidConditionException(
            pht('Regular expression pair is not valid JSON!'));
        }
        if (count($regexp_pair) != 2) {
          throw new HeraldInvalidConditionException(
            pht('Regular expression pair is not a pair!'));
        }

        $key_regexp   = array_shift($regexp_pair);
        $value_regexp = array_shift($regexp_pair);

        foreach ((array)$field_value as $key => $value) {
          $key_matches = @preg_match($key_regexp, $key);
          if ($key_matches === false) {
            throw new HeraldInvalidConditionException(
              pht('First regular expression is invalid!'));
          }
          if ($key_matches) {
            $value_matches = @preg_match($value_regexp, $value);
            if ($value_matches === false) {
              throw new HeraldInvalidConditionException(
                pht('Second regular expression is invalid!'));
            }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Store exactly two elements: json_encode(array('/key-regexp/', '/value-regexp/')).
  2. Re-save the condition in the Herald UI to normalize it.
  3. Add a count check in whatever automation writes these values before it saves the rule.

Example fix

// before
["/foo.*/", "/bar.*/", "/baz.*/"]

// after
["/foo.*/", "/bar.*/"]
Defensive patterns

Strategy: validation

Validate before calling

$pair = phutil_json_decode($value);
if (!is_array($pair) || count($pair) !== 2) {
  // fix the stored value: exactly [keyRegexp, valueRegexp]
}

Type guard

function isHeraldRegexpPairValue($value) {
  try {
    $pair = phutil_json_decode($value);
  } catch (PhutilJSONParserException $ex) {
    return false;
  }
  return is_array($pair) && count($pair) === 2;
}

Prevention

When it happens

Trigger: A regexp-pair condition value like ["/a/"] (one element), ["/a/", "/b/", "/c/"] (three), or a JSON object/empty array [] — again typically from API-written or migrated rule data rather than the UI.

Common situations: Scripts building pair values by naive string concatenation; edits that append a third pattern; empty array defaults from templates.

Related errors


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