phacility/phabricator · warning · PhutilArgumentUsageException
Publisher class '%s' must be a concrete subclass of %s.
Error message
Publisher class '%s' must be a concrete subclass of %s.
What it means
`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.
Source
Thrown at src/applications/diviner/workflow/DivinerGenerateWorkflow.php:187
//
// We walk the dirty list and compute the new graph hashes, adding them
// to the graph hash map. This Graph Map can then be passed to an actual
// documentation generator, which can compare the graph hashes to a list
// of already-generated graph hashes and easily assess which documents need
// to be regenerated and which can be deleted.
$this->buildAtomCache();
$this->buildGraphCache();
$publisher_class = $args->getArg('publisher');
$symbols = id(new PhutilSymbolLoader())
->setName($publisher_class)
->setConcreteOnly(true)
->setAncestorClass('DivinerPublisher')
->selectAndLoadSymbols();
if (!$symbols) {
throw new PhutilArgumentUsageException(
pht(
"Publisher class '%s' must be a concrete subclass of %s.",
$publisher_class,
'DivinerPublisher'));
}
$publisher = newv($publisher_class, array());
$identifier = $args->getArg('repository');
$repository = null;
if ($identifier !== null && strlen($identifier)) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withIdentifiers(array($identifier))
->executeOne();
if (!$repository) {
throw new PhutilArgumentUsageException(
pht(View on GitHub (pinned to 5720a38cfe)
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`
Example fix
# before diviner generate --publisher MyPublisherTypo # after diviner generate --publisher DivinerLivePublisher
Defensive patterns
Strategy: type-guard
Validate before calling
$publisher_class = $args->getArg('publisher', 'DivinerLivePublisher');
if (!is_concrete_publisher_class($publisher_class)) {
// Use the default publisher rather than failing.
$publisher_class = 'DivinerLivePublisher';
} Type guard
function is_concrete_publisher_class($class) {
if (!is_string($class) || !class_exists($class)) {
return false;
}
if (!is_subclass_of($class, 'DivinerPublisher')) {
return false;
}
return !(new ReflectionClass($class))->isAbstract();
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Atomizer class '%s' must be a concrete subclass of %s.
- Specify an atomizer class with %s.
- There are no Diviner '%s' files anywhere beneath the current
- Specify a device with --device.
- Specify a private key with --private-key.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/b9b2bc1356f2087f.
Report an issue: GitHub.