{"record":{"id":"3fbd07485a7dd034","repo":"phacility/phabricator","slug":"regular-expression-pair-is-not-a-pair","errorCode":null,"errorMessage":"Regular expression pair is not a pair!","messagePattern":"Regular expression pair is not a pair!","errorType":"validation","errorClass":"HeraldInvalidConditionException","httpStatus":null,"severity":"error","filePath":"src/applications/herald/adapter/HeraldAdapter.php","lineNumber":564,"sourceCode":"          if ($result) {\n            return $result_if_match;\n          }\n        }\n        return !$result_if_match;\n      case self::CONDITION_REGEXP_PAIR:\n        // Match a JSON-encoded pair of regular expressions against a\n        // dictionary. The first regexp must match the dictionary key, and the\n        // second regexp must match the dictionary value. If any key/value pair\n        // in the dictionary matches both regexps, the condition is satisfied.\n        $regexp_pair = null;\n        try {\n          $regexp_pair = phutil_json_decode($condition_value);\n        } catch (PhutilJSONParserException $ex) {\n          throw new HeraldInvalidConditionException(\n            pht('Regular expression pair is not valid JSON!'));\n        }\n        if (count($regexp_pair) != 2) {\n          throw new HeraldInvalidConditionException(\n            pht('Regular expression pair is not a pair!'));\n        }\n\n        $key_regexp   = array_shift($regexp_pair);\n        $value_regexp = array_shift($regexp_pair);\n\n        foreach ((array)$field_value as $key => $value) {\n          $key_matches = @preg_match($key_regexp, $key);\n          if ($key_matches === false) {\n            throw new HeraldInvalidConditionException(\n              pht('First regular expression is invalid!'));\n          }\n          if ($key_matches) {\n            $value_matches = @preg_match($value_regexp, $value);\n            if ($value_matches === false) {\n              throw new HeraldInvalidConditionException(\n                pht('Second regular expression is invalid!'));\n            }","sourceCodeStart":546,"sourceCodeEnd":582,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/herald/adapter/HeraldAdapter.php#L546-L582","documentation":"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.","triggerScenarios":"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.","commonSituations":"Scripts building pair values by naive string concatenation; edits that append a third pattern; empty array defaults from templates.","solutions":["Store exactly two elements: json_encode(array('/key-regexp/', '/value-regexp/')).","Re-save the condition in the Herald UI to normalize it.","Add a count check in whatever automation writes these values before it saves the rule."],"exampleFix":"// before\n[\"/foo.*/\", \"/bar.*/\", \"/baz.*/\"]\n\n// after\n[\"/foo.*/\", \"/bar.*/\"]","handlingStrategy":"validation","validationCode":"$pair = phutil_json_decode($value);\nif (!is_array($pair) || count($pair) !== 2) {\n  // fix the stored value: exactly [keyRegexp, valueRegexp]\n}","typeGuard":"function isHeraldRegexpPairValue($value) {\n  try {\n    $pair = phutil_json_decode($value);\n  } catch (PhutilJSONParserException $ex) {\n    return false;\n  }\n  return is_array($pair) && count($pair) === 2;\n}","tryCatchPattern":null,"preventionTips":["Emit exactly two elements when generating regexp pairs.","Add a count check to any script that writes herald_condition values for REGEXP_PAIR."],"tags":["herald","regex","json","phabricator"],"backgroundTag":"invalid-json-payload","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}