{"record":{"id":"f303aeb9376d1626","repo":"phacility/phabricator","slug":"job-actor-does-not-have-permission-to-edit-job","errorCode":null,"errorMessage":"Job actor does not have permission to edit job.","messagePattern":"Job actor does not have permission to edit job\\.","errorType":"exception","errorClass":"PhabricatorWorkerPermanentFailureException","httpStatus":null,"severity":"error","filePath":"src/infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobWorker.php","lineNumber":76,"sourceCode":"\n  final protected function loadActor(PhabricatorWorkerBulkJob $job) {\n    $actor_phid = $job->getAuthorPHID();\n    $actor = id(new PhabricatorPeopleQuery())\n      ->setViewer(PhabricatorUser::getOmnipotentUser())\n      ->withPHIDs(array($actor_phid))\n      ->executeOne();\n    if (!$actor) {\n      throw new PhabricatorWorkerPermanentFailureException(\n        pht('Worker has invalid actor PHID (\"%s\").', $actor_phid));\n    }\n\n    $can_edit = PhabricatorPolicyFilter::hasCapability(\n      $actor,\n      $job,\n      PhabricatorPolicyCapability::CAN_EDIT);\n\n    if (!$can_edit) {\n      throw new PhabricatorWorkerPermanentFailureException(\n        pht('Job actor does not have permission to edit job.'));\n    }\n\n    // Allow the worker to fill user caches inline; bulk jobs occasionally\n    // need to access user preferences.\n    $actor->setAllowInlineCacheGeneration(true);\n\n    return $actor;\n  }\n\n  final protected function updateJob(PhabricatorWorkerBulkJob $job) {\n    $has_work = $this->hasRemainingWork($job);\n    if ($has_work) {\n      return;\n    }\n\n    $lock = $this->acquireJobLock();\n","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobWorker.php#L58-L94","documentation":"Before doing any work, bulk workers verify via PhabricatorPolicyFilter::hasCapability() that the job's author still holds CAN_EDIT on the job; if not, the task permanently fails. The check ensures a queued job cannot keep acting with authority its author no longer legitimately has.","triggerScenarios":"The job's edit policy (or that of its container) was tightened after the job was queued so the author lost edit access; the author's roles/approvals changed; the author account was disabled in a way that revokes edit capability.","commonSituations":"Policy tightening on projects or objects while bulk jobs are pending; compliance-driven permission revocations; policy recomputation after upgrades or migrations.","solutions":["Check the job's edit policy and the author's current access in the UI.","Either restore the author's edit capability on the job or cancel the job — it cannot proceed otherwise.","For custom job types, keep queued jobs under policies their authors will retain."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"$can_edit = PhabricatorPolicyFilter::hasCapability(\n  $author,\n  $job,\n  PhabricatorPolicyCapability::CAN_EDIT);\nif (!$can_edit) {\n  // do not queue the job: the worker will permanently fail\n}","typeGuard":null,"tryCatchPattern":"try {\n  // run the bulk worker\n} catch (PhabricatorWorkerPermanentFailureException $ex) {\n  // policy drift: re-grant edit or cancel the job; retrying will not help\n}","preventionTips":["Avoid tightening job/container edit policies while bulk jobs are pending.","Cancel pending jobs before revoking an author's edit access.","Queue jobs under policies their authors will keep for the job's lifetime."],"tags":["phabricator","bulk-jobs","policy","permissions"],"backgroundTag":"permission-denied","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}