{"record":{"id":"633135591884c64b","repo":"phacility/phabricator","slug":"book-configuration-s-has-name-s-but-book-na","errorCode":null,"errorMessage":"Book configuration '%s' has name '%s', but book names must include only lowercase letters and hyphens.","messagePattern":"Book configuration '(.+?)' has name '(.+?)', but book names must include only lowercase letters and hyphens\\.","errorType":"console","errorClass":"PhutilArgumentUsageException","httpStatus":null,"severity":"warning","filePath":"src/applications/diviner/workflow/DivinerWorkflow.php","lineNumber":55,"sourceCode":"        'preface' => 'optional string',\n        'root' => 'optional string',\n        'uri.source' => 'optional string',\n        'rules' => 'optional map<regex, string>',\n        'exclude' => 'optional regex|list<regex>',\n        'groups' => 'optional map<string, map<string, wild>>',\n      ));\n\n    // If the book specifies a \"root\", resolve it; otherwise, use the directory\n    // the book configuration file lives in.\n    $full_path = dirname(Filesystem::resolvePath($book_path));\n    if (empty($book['root'])) {\n      $book['root'] = '.';\n    }\n    $book['root'] = Filesystem::resolvePath($book['root'], $full_path);\n\n    if (!preg_match('/^[a-z][a-z-]*\\z/', $book['name'])) {\n      $name = $book['name'];\n      throw new PhutilArgumentUsageException(\n        pht(\n          \"Book configuration '%s' has name '%s', but book names must \".\n          \"include only lowercase letters and hyphens.\",\n          $book_path,\n          $name));\n    }\n\n    foreach (idx($book, 'groups', array()) as $group) {\n      PhutilTypeSpec::checkMap(\n        $group,\n        array(\n          'name' => 'string',\n          'include' => 'optional regex|list<regex>',\n        ));\n    }\n\n    $this->bookConfigPath = $book_path;\n    $this->config = $book;","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/diviner/workflow/DivinerWorkflow.php#L37-L73","documentation":"When loading a book configuration, Diviner enforces that the `name` field matches `/^[a-z][a-z-]*\\z/`. The name becomes part of the on-disk atom cache path and generated URIs, so uppercase letters, digits, underscores, or a leading hyphen are rejected with this PhutilArgumentUsageException. The message includes both the offending book path and the rejected name.","triggerScenarios":"A `.book` JSON whose `name` is e.g. \"PhabDocs\", \"docs2\", \"my_book\", or \"-docs\". Any character outside a-z and hyphen, or a name not starting with a letter, triggers it.","commonSituations":"Naming the book after the product with CamelCase (\"PhabricatorDocs\"); converting a repo name like \"my_docs\" directly into a book name; renaming a book later and forgetting the constraint.","solutions":["Rewrite the name to lowercase letters and hyphens only: \"PhabDocs\" -> \"phab-docs\"","Keep `title` (human-readable) separate — the constraint applies only to `name`","After renaming, clear stale `.divinercache` directories named after the old book"],"exampleFix":"// before (docs/book.book)\n\"name\": \"PhabricatorDocs\",\n// after\n\"name\": \"phabricator-docs\",","handlingStrategy":"validation","validationCode":"$name = idx($book, 'name');\nif (!preg_match('/^[a-z][a-z-]*\\z/', $name)) {\n  // Fix the name before shipping the .book file.\n  $book['name'] = strtolower(preg_replace('/[^a-z-]+/i', '-', $name));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use only lowercase letters and hyphens in `name`; put display text in `title`","Add a CI lint that validates book names against ^[a-z][a-z-]*\\z","After renaming, delete the old .divinercache directory to avoid stale caches"],"tags":["diviner","config","validation","naming","phabricator"],"backgroundTag":"config-validation-failed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}