{"record":{"id":"12fca9509e383e00","repo":"phacility/phabricator","slug":"webhook-request-s-is-not-in-s-status-actu","errorCode":null,"errorMessage":"Webhook request (\"%s\") is not in \"%s\" status (actual status is \"%s\"). Declining call to hook.","messagePattern":"Webhook request \\(\"(.+?)\"\\) is not in \"(.+?)\" status \\(actual status is \"(.+?)\"\\)\\. Declining call to hook\\.","errorType":"exception","errorClass":"PhabricatorWorkerPermanentFailureException","httpStatus":null,"severity":"error","filePath":"src/applications/herald/worker/HeraldWebhookWorker.php","lineNumber":26,"sourceCode":"\n    $data = $this->getTaskData();\n    $request_phid = idx($data, 'webhookRequestPHID');\n\n    $request = id(new HeraldWebhookRequestQuery())\n      ->setViewer($viewer)\n      ->withPHIDs(array($request_phid))\n      ->executeOne();\n    if (!$request) {\n      throw new PhabricatorWorkerPermanentFailureException(\n        pht(\n          'Unable to load webhook request (\"%s\"). It may have been '.\n          'garbage collected.',\n          $request_phid));\n    }\n\n    $status = $request->getStatus();\n    if ($status !== HeraldWebhookRequest::STATUS_QUEUED) {\n      throw new PhabricatorWorkerPermanentFailureException(\n        pht(\n          'Webhook request (\"%s\") is not in \"%s\" status (actual '.\n          'status is \"%s\"). Declining call to hook.',\n          $request_phid,\n          HeraldWebhookRequest::STATUS_QUEUED,\n          $status));\n    }\n\n    // If we're in silent mode, permanently fail the webhook request and then\n    // return to complete this task.\n    if (PhabricatorEnv::getEnvConfig('phabricator.silent')) {\n      $this->failRequest(\n        $request,\n        HeraldWebhookRequest::ERRORTYPE_HOOK,\n        HeraldWebhookRequest::ERROR_SILENT);\n      return;\n    }\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/herald/worker/HeraldWebhookWorker.php#L8-L44","documentation":"The webhook worker only delivers a request whose status is STATUS_QUEUED; any other status means the request was already sent or failed, so the task permanently fails instead of double-calling the hook. This almost always means the same request was processed twice -- a duplicate queued task or a retry that raced a completed attempt.","triggerScenarios":"Two worker tasks enqueued for the same request PHID; a task retried (lease expiry) after the first attempt already updated the request to SENT/FAILED; manual status changes on the request row.","commonSituations":"Queue backlog replayed after a restore; duplicate task insertion during high load; a retried timeout task whose first attempt actually succeeded.","solutions":["Inspect the request in the Webhooks UI -- it already has a terminal status, so no further action is needed for that request.","If you need another delivery, fire a fresh request via './bin/herald call-webhook --id <hook> --object <object>'.","Let the duplicate task die: permanent failure removes it from the queue without retries."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// In any custom processor, re-check status before acting on a request:\n$request = id(new HeraldWebhookRequestQuery())\n  ->setViewer($viewer)\n  ->withPHIDs(array($request_phid))\n  ->executeOne();\nif (!$request || $request->getStatus() !== HeraldWebhookRequest::STATUS_QUEUED) {\n  return; // already handled elsewhere; skip instead of double-delivering\n}","typeGuard":null,"tryCatchPattern":"try {\n  // process queued webhook request\n} catch (PhabricatorWorkerPermanentFailureException $ex) {\n  // duplicate/stale task: the request already reached a terminal status\n  phlog($ex->getMessage());\n}","preventionTips":["Never assume a dequeued task is the only attempt for a request; always re-read its status.","Make webhook handling idempotent keyed on the request PHID."],"tags":["herald","webhook","phabricator","worker","idempotency"],"backgroundTag":"invalid-state-transition","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}