phacility/phabricator · error · HeraldInvalidConditionException

Regular expression pair is not valid JSON!

Error message

Regular expression pair is not valid JSON!

What it means

The CONDITION_REGEXP_PAIR condition stores a JSON-encoded pair of regular expressions (key regexp, value regexp) to match against dictionary field values. The adapter phutil_json_decode()s the stored condition value; if it is not valid JSON, PhutilJSONParserException is caught and rethrown as HeraldInvalidConditionException('Regular expression pair is not valid JSON!').

Source

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

            throw new HeraldInvalidConditionException($message);
          }

          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);

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Set the condition value to a JSON-encoded array of exactly two regexp strings, e.g. json_encode(array('/key-regex/', '/value-regex/')).
  2. Re-save the rule through the Herald UI so the editor rewrites the value in the correct format.
  3. If it keeps recurring, audit whatever script/integration writes the rule value and fix it to emit JSON.

Example fix

// before (stored condition value)
foo.*,bar.*

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

Strategy: validation

Validate before calling

// Pre-validate a regexp-pair condition value before saving:
try {
  $pair = phutil_json_decode($value);
} catch (PhutilJSONParserException $ex) {
  $pair = null;
}
if (!is_array($pair)) {
  $value = phutil_json_encode(array('/key-pattern/', '/value-pattern/'));
}

Prevention

When it happens

Trigger: A rule with a 'regexp pair' condition whose stored value is a plain string like 'foo,bar' or unquoted/malformed JSON — usually created via the Conduit API or a migration script, since the web editor stores valid JSON.

Common situations: herald.rule.edit calls that pass a raw string instead of a JSON-encoded array; hand-edited herald_condition rows; rules imported from another instance with mangled escaping.

Related errors


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