phacility/phabricator · error · Exception

Unknown search engine class "%s".

Error message

Unknown search engine class "%s".

What it means

Bulk export jobs serialize the search engine class name in the PhabricatorWorkerBulkJob parameters; when a task runs, PhabricatorExportEngineBulkJobType::runTask() re-instantiates it. The guard is_subclass_of($engine_class, 'PhabricatorApplicationSearchEngine') fails when the stored class no longer exists, was renamed, or never was a search engine, so the job cannot proceed and the worker task errors out. This protects against arbitrary class instantiation from job payloads (a mass-assignment/RCE-shaped risk) as well as plain drift.

Source

Thrown at src/infrastructure/export/engine/PhabricatorExportEngineBulkJobType.php:56

        $actions[] = id(new PhabricatorActionView())
          ->setHref($file->getDownloadURI())
          ->setIcon('fa-download')
          ->setName(pht('Download Data Export'));
      }
    }

    return $actions;
  }


  public function runTask(
    PhabricatorUser $actor,
    PhabricatorWorkerBulkJob $job,
    PhabricatorWorkerBulkTask $task) {

    $engine_class = $job->getParameter('engineClass');
    if (!is_subclass_of($engine_class, 'PhabricatorApplicationSearchEngine')) {
      throw new Exception(
        pht(
          'Unknown search engine class "%s".',
          $engine_class));
    }

    $engine = newv($engine_class, array())
      ->setViewer($actor);

    $query_key = $job->getParameter('queryKey');
    if ($engine->isBuiltinQuery($query_key)) {
      $saved_query = $engine->buildSavedQueryFromBuiltin($query_key);
    } else if ($query_key) {
      $saved_query = id(new PhabricatorSavedQueryQuery())
        ->setViewer($actor)
        ->withQueryKeys(array($query_key))
        ->executeOne();
    } else {
      $saved_query = null;

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Restore the class: re-enable the extension/application that provides the search engine, then let the worker retry the failed tasks (or re-queue them).
  2. If the class is gone for good, cancel the bulk job in Daemons > Bulk Jobs (or via the job's UI) and re-run the export from a query that still exists.
  3. For deployments that rename engine classes, drain or complete queued export jobs before the rename ships.

Example fix

// before: extension disabled, queued job references missing engine
$engine_class = $job->getParameter('engineClass'); // 'MyExtThingSearchEngine'
if (!is_subclass_of($engine_class, 'PhabricatorApplicationSearchEngine')) {
  throw new Exception(...); // worker task fails
}

// after: keep the class loadable (do not disable the app mid-queue), or pre-check when enqueueing
if (!is_subclass_of($engine_class, 'PhabricatorApplicationSearchEngine')) {
  throw new Exception(pht('...')); // validate BEFORE queuing the bulk job
}
Defensive patterns

Strategy: validation

Validate before calling

$engine_class = $job->getParameter('engineClass');
if (!is_subclass_of($engine_class, 'PhabricatorApplicationSearchEngine')) {
  throw new Exception(pht('Search engine class no longer available: %s', $engine_class));
}

Type guard

function isValidSearchEngineClass($class) {
  return is_string($class)
    && class_exists($class)
    && is_subclass_of($class, 'PhabricatorApplicationSearchEngine');
}

Try / catch

try {
  $this->runTask($actor, $job, $task);
} catch (Exception $ex) {
  // permanent failure: do not retry; mark task failed and surface in Bulk Job UI
  throw new PhabricatorWorkerPermanentFailureException($ex->getMessage());
}

Prevention

When it happens

Trigger: A user queues 'Export to CSV/Excel' from a query powered by a custom/extension search engine, then the extension is disabled, uninstalled, or renamed before the worker task executes - runTask() gets engineClass 'MyExtensionFancySearchEngine' which is no longer loaded; likewise a hand-crafted/corrupted bulk job row.

Common situations: Disabling or upgrading an application right as exports are queued; deploying a refactor that renames engine classes while old bulk jobs linger in the queue; database copies (staging clones of prod) missing the extension code that prod had.

Related errors


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