{"record":{"id":"b9b2bc1356f2087f","repo":"phacility/phabricator","slug":"publisher-class-s-must-be-a-concrete-subclass-o","errorCode":null,"errorMessage":"Publisher class '%s' must be a concrete subclass of %s.","messagePattern":"Publisher class '(.+?)' must be a concrete subclass of (.+?)\\.","errorType":"console","errorClass":"PhutilArgumentUsageException","httpStatus":null,"severity":"warning","filePath":"src/applications/diviner/workflow/DivinerGenerateWorkflow.php","lineNumber":187,"sourceCode":"    //\n    // We walk the dirty list and compute the new graph hashes, adding them\n    // to the graph hash map. This Graph Map can then be passed to an actual\n    // documentation generator, which can compare the graph hashes to a list\n    // of already-generated graph hashes and easily assess which documents need\n    // to be regenerated and which can be deleted.\n\n    $this->buildAtomCache();\n    $this->buildGraphCache();\n\n    $publisher_class = $args->getArg('publisher');\n    $symbols = id(new PhutilSymbolLoader())\n      ->setName($publisher_class)\n      ->setConcreteOnly(true)\n      ->setAncestorClass('DivinerPublisher')\n      ->selectAndLoadSymbols();\n\n    if (!$symbols) {\n      throw new PhutilArgumentUsageException(\n        pht(\n          \"Publisher class '%s' must be a concrete subclass of %s.\",\n          $publisher_class,\n          'DivinerPublisher'));\n    }\n    $publisher = newv($publisher_class, array());\n\n    $identifier = $args->getArg('repository');\n    $repository = null;\n    if ($identifier !== null && strlen($identifier)) {\n      $repository = id(new PhabricatorRepositoryQuery())\n        ->setViewer(PhabricatorUser::getOmnipotentUser())\n        ->withIdentifiers(array($identifier))\n        ->executeOne();\n\n      if (!$repository) {\n        throw new PhutilArgumentUsageException(\n          pht(","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/diviner/workflow/DivinerGenerateWorkflow.php#L169-L205","documentation":"`diviner generate` renders atoms through a publisher resolved from `--publisher` (default DivinerLivePublisher). The class is checked with PhutilSymbolLoader for a concrete subclass of DivinerPublisher; if no symbol is selected, this usage exception is thrown. It means the publisher class name is not a loadable, concrete DivinerPublisher subclass.","triggerScenarios":"Passing `--publisher SomeClass` that is misspelled, abstract, not a DivinerPublisher subclass, or lives in a phutil library not loaded in the Diviner environment. The default value never triggers this, only an explicit override can.","commonSituations":"Pointing `--publisher` at a custom static-site publisher class that was moved or renamed between Phabricator versions; writing a custom publisher and forgetting to make it concrete; class file present but library not in the phutil load path.","solutions":["Drop the `--publisher` flag to use the default DivinerLivePublisher","Verify the class name spelling, case, and that its library is loaded","Make the custom class non-abstract and declare `extends DivinerPublisher`"],"exampleFix":"# before\ndiviner generate --publisher MyPublisherTypo\n# after\ndiviner generate --publisher DivinerLivePublisher","handlingStrategy":"type-guard","validationCode":"$publisher_class = $args->getArg('publisher', 'DivinerLivePublisher');\nif (!is_concrete_publisher_class($publisher_class)) {\n  // Use the default publisher rather than failing.\n  $publisher_class = 'DivinerLivePublisher';\n}","typeGuard":"function is_concrete_publisher_class($class) {\n  if (!is_string($class) || !class_exists($class)) {\n    return false;\n  }\n  if (!is_subclass_of($class, 'DivinerPublisher')) {\n    return false;\n  }\n  return !(new ReflectionClass($class))->isAbstract();\n}","tryCatchPattern":null,"preventionTips":["Omit --publisher to use the default DivinerLivePublisher","Add a load test for custom publisher classes after every Phabricator upgrade","Keep custom publishers in a phutil library that the diviner environment loads"],"tags":["diviner","cli","class-loading","usage-error","phabricator"],"backgroundTag":"class-not-subclass","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}