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

  1. Drop the `--publisher` flag to use the default DivinerLivePublisher
  2. Verify the class name spelling, case, and that its library is loaded
  3. 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

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


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/b9b2bc1356f2087f. Report an issue: GitHub.