phacility/phabricator · error · PhabricatorWorkerPermanentFailureException

Worker has no job ID.

Error message

Worker has no job ID.

What it means

Bulk job workers receive their job identity through the 'jobID' key of the worker task data; getJobID() permanently fails the task when that key is missing or falsy. Core always sets jobID when queuing, so hitting this means a custom scheduler queued a bulk worker class directly with wrong or missing task data.

Source

Thrown at src/infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobWorker.php:20

abstract class PhabricatorWorkerBulkJobWorker
  extends PhabricatorWorker {

  final protected function acquireJobLock() {
    return PhabricatorGlobalLock::newLock('bulkjob.'.$this->getJobID())
      ->lock(15);
  }

  final protected function acquireTaskLock() {
    return PhabricatorGlobalLock::newLock('bulktask.'.$this->getTaskID())
      ->lock(15);
  }

  final protected function getJobID() {
    $data = $this->getTaskData();
    $id = idx($data, 'jobID');
    if (!$id) {
      throw new PhabricatorWorkerPermanentFailureException(
        pht('Worker has no job ID.'));
    }
    return $id;
  }

  final protected function getTaskID() {
    $data = $this->getTaskData();
    $id = idx($data, 'taskID');
    if (!$id) {
      throw new PhabricatorWorkerPermanentFailureException(
        pht('Worker has no task ID.'));
    }
    return $id;
  }

  final protected function loadJob() {
    $id = $this->getJobID();
    $job = id(new PhabricatorWorkerBulkJobQuery())

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Schedule bulk workers with array('jobID' => $job->getID()) (plus 'taskID' where the worker needs it).
  2. Prefer the job's own queue/confirm flow rather than scheduleTask() on the worker class.
  3. Align custom schedulers' task-data keys with core's expectations.

Example fix

// before
PhabricatorWorker::scheduleTask(
  'PhabricatorWorkerBulkJobCreateWorker',
  array());

// after
PhabricatorWorker::scheduleTask(
  'PhabricatorWorkerBulkJobCreateWorker',
  array('jobID' => $job->getID()));
Defensive patterns

Strategy: validation

Validate before calling

if (!idx($task_data, 'jobID')) {
  throw new InvalidArgumentException(
    'Bulk worker task data requires a jobID.');
}
PhabricatorWorker::scheduleTask($bulk_worker_class, $task_data);

Type guard

function bulk_task_data_has_job_id($data) {
  return is_array($data) && !empty($data['jobID']);
}

Prevention

When it happens

Trigger: Calling PhabricatorWorker::scheduleTask() on PhabricatorWorkerBulkJobCreateWorker (or a custom PhabricatorWorkerBulkJobWorker subclass) with a data array that lacks 'jobID', or where the jobID value is 0/null.

Common situations: Custom code queuing bulk workers directly instead of going through PhabricatorWorkerBulkJob's own queue pipeline; refactors that renamed or dropped the task-data key.

Related errors


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