phacility/phabricator · error · HeraldInvalidConditionException

The regular expression pair "%s" must have exactly two eleme

Error message

The regular expression pair "%s" must have exactly two elements.

What it means

Thrown by HeraldAdapter::willSaveCondition() for CONDITION_REGEXP_PAIR after the value parsed successfully as JSON but count($json) != 2. The pair condition semantically requires exactly two elements — a key regexp and a value regexp — so arrays with fewer or more elements are rejected even though they are valid JSON.

Source

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

              'must have enclosing characters (e.g. "@/path/to/file@", not '.
              '"/path/to/file") and be syntactically correct.',
              $condition_value));
        }
        break;
      case self::CONDITION_REGEXP_PAIR:
        $json = null;
        try {
          $json = phutil_json_decode($condition_value);
        } catch (PhutilJSONParserException $ex) {
          throw new HeraldInvalidConditionException(
            pht(
              'The regular expression pair "%s" is not valid JSON. Enter a '.
              'valid JSON array with two elements.',
              $condition_value));
        }

        if (count($json) != 2) {
          throw new HeraldInvalidConditionException(
            pht(
              'The regular expression pair "%s" must have exactly two '.
              'elements.',
              $condition_value));
        }

        $key_regexp = array_shift($json);
        $val_regexp = array_shift($json);

        $key_ok = @preg_match($key_regexp, '');
        if ($key_ok === false) {
          throw new HeraldInvalidConditionException(
            pht(
              'The first regexp in the regexp pair, "%s", is not a valid '.
              'regexp.',
              $key_regexp));
        }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Make the value a JSON array with exactly two string elements: ["@key@", "@value@"].
  2. Combine multiple key patterns into one regexp with alternation, e.g. "@^(this|that)@" instead of adding a third array element.
  3. Remove empty strings or null placeholders left over from drafting.

Example fix

// before
["@^title$@", "@^urgent@", "@^asap@"]

// after
["@^(title|summary)$@", "@(urgent|asap)@"]
Defensive patterns

Strategy: validation

Validate before calling

$json = phutil_json_decode($value); // assume decode succeeded
if (!is_array($json) || count($json) !== 2) {
  return pht('Regexp pair must contain exactly two patterns.');
}

Type guard

function isHeraldRegexpPair($decoded) {
  return is_array($decoded) && count($decoded) === 2
    && isset($decoded[0]) && isset($decoded[1]);
}

Try / catch

try {
  $editor->save();
} catch (HeraldInvalidConditionException $ex) {
  // check the message: 'exactly two elements' means fix the array shape,
  // not the regexes themselves
}

Prevention

When it happens

Trigger: Saving a regexp-pair condition whose JSON decodes to an array of length other than 2: [] , ["@only-key@"], or ["@a@", "@b@", "@c@"]. The count() check runs immediately after phutil_json_decode() succeeds.

Common situations: Users assume the pair is a list and add several patterns, or leave a placeholder/empty array while drafting a rule. Occasionally a JSON array containing a nested array (e.g. [["a"], "b"]) still passes count but fails the later regexp checks.

Related errors


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