phacility/phabricator · warning · PhutilArgumentUsageException

This source ("%s") does not expose import cursors.

Error message

This source ("%s") does not expose import cursors.

What it means

Nuance management workflow (bin/nuance import ...) guard: after loading the requested NuanceSource, the code asks its definition (NuanceSourceDefinition with viewer and source set) whether it implements import cursors at all via hasImportCursors(). Source types that do no period polling (no cursor concept) cannot be imported on demand, so a PhutilArgumentUsageException stops the run immediately.

Source

Thrown at src/applications/nuance/management/NuanceManagementImportWorkflow.php:34

            'help' => pht('Choose which source to import.'),
          ),
          array(
            'name' => 'cursor',
            'param' => 'cursor',
            'help' => pht('Import only a particular cursor.'),
          ),
        ));
  }

  public function execute(PhutilArgumentParser $args) {
    $source = $this->loadSource($args, 'source');

    $definition = $source->getDefinition()
      ->setViewer($this->getViewer())
      ->setSource($source);

    if (!$definition->hasImportCursors()) {
      throw new PhutilArgumentUsageException(
        pht(
          'This source ("%s") does not expose import cursors.',
          $source->getName()));
    }

    $cursors = $definition->getImportCursors();
    if (!$cursors) {
      throw new PhutilArgumentUsageException(
        pht(
          'This source ("%s") does not have any import cursors.',
          $source->getName()));
    }

    $select = $args->getArg('cursor');
    if (strlen($select)) {
      if (empty($cursors[$select])) {
        throw new PhutilArgumentUsageException(
          pht(

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Confirm the source type actually supports cursored import (check the definition class's hasImportCursors()/getImportCursors()); if not, use the source's intended ingestion path instead of the import command.
  2. If the type SHOULD support import (custom definition), implement getImportCursors() and make hasImportCursors() return true, then rerun.
  3. Pick a different source that does expose cursors — e.g. a polling-type source — if you were just testing the workflow.
  4. Script defensively: filter the source list by cursor support before invoking import.

Example fix

// before:
class MyNuanceSourceDefinition extends NuanceSourceDefinition {
  // no getImportCursors() / hasImportCursors() defaults false
}
// bin/nuance import --source 12 -> err: "does not expose import cursors"

// after:
public function hasImportCursors() { return true; }
public function getImportCursors() {
  return array(new MyNuanceImportCursor());
}
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking the import workflow, check the same predicate:
$definition = id(new NuanceSourceQuery())
  ->setViewer($viewer)
  ->withIDs(array($source_id))
  ->executeOne()
  ->getDefinition()
  ->setViewer($viewer);
if (!$definition->hasImportCursors()) {
  // skip: this source type cannot be imported on demand
}

Prevention

When it happens

Trigger: Running 'bin/nuance import --source <source>' (or the specific import workflow that calls loadSource then getDefinition()->hasImportCursors()) where the source's definition type returns false from hasImportCursors() — e.g. a Twitter or other one-shot/webhook-style source type whose definition never implements getImportCursors().

Common situations: Operators attempting a manual backfill/poll on a source type that only receives pushed data; scripted retry loops that treat every source uniformly; a custom source definition written without cursor support being exercised by the standard import command for the first time.

Related errors


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