{"record":{"id":"ad1294d28e1255d1","repo":"phacility/phabricator","slug":"worker-has-no-job-id","errorCode":null,"errorMessage":"Worker has no job ID.","messagePattern":"Worker has no job ID\\.","errorType":"exception","errorClass":"PhabricatorWorkerPermanentFailureException","httpStatus":null,"severity":"error","filePath":"src/infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobWorker.php","lineNumber":20,"sourceCode":"\nabstract class PhabricatorWorkerBulkJobWorker\n  extends PhabricatorWorker {\n\n  final protected function acquireJobLock() {\n    return PhabricatorGlobalLock::newLock('bulkjob.'.$this->getJobID())\n      ->lock(15);\n  }\n\n  final protected function acquireTaskLock() {\n    return PhabricatorGlobalLock::newLock('bulktask.'.$this->getTaskID())\n      ->lock(15);\n  }\n\n  final protected function getJobID() {\n    $data = $this->getTaskData();\n    $id = idx($data, 'jobID');\n    if (!$id) {\n      throw new PhabricatorWorkerPermanentFailureException(\n        pht('Worker has no job ID.'));\n    }\n    return $id;\n  }\n\n  final protected function getTaskID() {\n    $data = $this->getTaskData();\n    $id = idx($data, 'taskID');\n    if (!$id) {\n      throw new PhabricatorWorkerPermanentFailureException(\n        pht('Worker has no task ID.'));\n    }\n    return $id;\n  }\n\n  final protected function loadJob() {\n    $id = $this->getJobID();\n    $job = id(new PhabricatorWorkerBulkJobQuery())","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobWorker.php#L2-L38","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom code queuing bulk workers directly instead of going through PhabricatorWorkerBulkJob's own queue pipeline; refactors that renamed or dropped the task-data key.","solutions":["Schedule bulk workers with array('jobID' => $job->getID()) (plus 'taskID' where the worker needs it).","Prefer the job's own queue/confirm flow rather than scheduleTask() on the worker class.","Align custom schedulers' task-data keys with core's expectations."],"exampleFix":"// before\nPhabricatorWorker::scheduleTask(\n  'PhabricatorWorkerBulkJobCreateWorker',\n  array());\n\n// after\nPhabricatorWorker::scheduleTask(\n  'PhabricatorWorkerBulkJobCreateWorker',\n  array('jobID' => $job->getID()));","handlingStrategy":"validation","validationCode":"if (!idx($task_data, 'jobID')) {\n  throw new InvalidArgumentException(\n    'Bulk worker task data requires a jobID.');\n}\nPhabricatorWorker::scheduleTask($bulk_worker_class, $task_data);","typeGuard":"function bulk_task_data_has_job_id($data) {\n  return is_array($data) && !empty($data['jobID']);\n}","tryCatchPattern":null,"preventionTips":["Always schedule bulk workers with array('jobID' => ...).","Use the job's own pipeline instead of scheduleTask() on worker classes.","Keep task-data keys identical to core's when subclassing bulk workers."],"tags":["phabricator","bulk-jobs","worker-queue","task-data"],"backgroundTag":"missing-task-data","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}