{"record":{"id":"d5ca0c634af6e10d","repo":"phacility/phabricator","slug":"rule-s-is-not-a-valid-regular-expression","errorCode":null,"errorMessage":"Rule '%s' is not a valid regular expression.","messagePattern":"Rule '(.+?)' is not a valid regular expression\\.","errorType":"console","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/diviner/workflow/DivinerGenerateWorkflow.php","lineNumber":275,"sourceCode":"    $this->log(pht('Done.').\"\\n\");\n  }\n\n  private function getAtomizersForFiles(array $files) {\n    $rules = $this->getRules();\n    $exclude = $this->getExclude();\n    $atomizers = array();\n\n    foreach ($files as $file) {\n      foreach ($exclude as $pattern) {\n        if (preg_match($pattern, $file)) {\n          continue 2;\n        }\n      }\n\n      foreach ($rules as $rule => $atomizer) {\n        $ok = preg_match($rule, $file);\n        if ($ok === false) {\n          throw new Exception(\n            pht(\"Rule '%s' is not a valid regular expression.\", $rule));\n        }\n        if ($ok) {\n          $atomizers[$file] = $atomizer;\n          continue;\n        }\n      }\n    }\n\n    return $atomizers;\n  }\n\n  private function getRules() {\n    return $this->getConfig('rules', array(\n      '/\\\\.diviner$/' => 'DivinerArticleAtomizer',\n      '/\\\\.php$/' => 'DivinerPHPAtomizer',\n    ));\n  }","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/diviner/workflow/DivinerGenerateWorkflow.php#L257-L293","documentation":"While distributing files to atomizers, Diviner runs each `rules` key from the book configuration through preg_match(). PHP's preg_match returns false for a malformed pattern, and this Exception is thrown for the first rule that fails. In practice it almost always means the `.book` JSON has a rule key that is not a valid PCRE pattern — most commonly missing the delimiter characters (`/.../`) that PHP requires.","triggerScenarios":"A `.book` file containing e.g. `\"rules\": {\"\\.php$\": \"DivinerPHPAtomizer\"}` — the key lacks delimiters, so preg_match returns false. Also unbalanced parentheses/brackets, unknown modifiers after the closing delimiter, or a stray backslash.","commonSituations":"Authors writing regexes JSON-style (without delimiters) as in JS or Python; regexes that worked in another tool but were pasted into the `.book` file losing their delimiters; escaping mistakes through the double layer of JSON + PCRE (e.g. `\\\\.` needed for a literal dot).","solutions":["Wrap every rule key in delimiters: `\"\\\\.php$\"` becomes `\"/\\\\.php$/\"`","Test each pattern in isolation: `php -r 'var_dump(preg_match(\"/PATTERN/\", \"\"));'` should not print false","Run a JSON lint on the `.book` file after editing to catch escaping damage"],"exampleFix":"// before (docs/book.book)\n\"rules\": {\"src/.*\\\\.php$\": \"DivinerPHPAtomizer\"}\n// after (PCRE delimiters added)\n\"rules\": {\"/src/.*\\\\.php$/\": \"DivinerPHPAtomizer\"}","handlingStrategy":"validation","validationCode":"$rules = idx($book, 'rules', array());\nforeach (array_keys($rules) as $rule) {\n  if (@preg_match($rule, '') === false) {\n    // Reject the config before Diviner runs: the pattern is not valid PCRE.\n    throw new Exception('Invalid regex in book config: '.$rule);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Every rules key needs PCRE delimiters (e.g. \"/\\.php$/\"), unlike JS/Python regex","Test patterns standalone: php -r 'var_dump(preg_match(\"/YOUR_PATTERN/\", \"\"));'","Add a .book linter step to CI that runs the @preg_match pre-check on every rule"],"tags":["diviner","regex","config","pcre","phabricator"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}