phacility/phabricator · error · PhabricatorWorkerPermanentFailureException

Webhook request ("%s") is not in "%s" status (actual status

Error message

Webhook request ("%s") is not in "%s" status (actual status is "%s"). Declining call to hook.

What it means

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.

Source

Thrown at src/applications/herald/worker/HeraldWebhookWorker.php:26

    $data = $this->getTaskData();
    $request_phid = idx($data, 'webhookRequestPHID');

    $request = id(new HeraldWebhookRequestQuery())
      ->setViewer($viewer)
      ->withPHIDs(array($request_phid))
      ->executeOne();
    if (!$request) {
      throw new PhabricatorWorkerPermanentFailureException(
        pht(
          'Unable to load webhook request ("%s"). It may have been '.
          'garbage collected.',
          $request_phid));
    }

    $status = $request->getStatus();
    if ($status !== HeraldWebhookRequest::STATUS_QUEUED) {
      throw new PhabricatorWorkerPermanentFailureException(
        pht(
          'Webhook request ("%s") is not in "%s" status (actual '.
          'status is "%s"). Declining call to hook.',
          $request_phid,
          HeraldWebhookRequest::STATUS_QUEUED,
          $status));
    }

    // If we're in silent mode, permanently fail the webhook request and then
    // return to complete this task.
    if (PhabricatorEnv::getEnvConfig('phabricator.silent')) {
      $this->failRequest(
        $request,
        HeraldWebhookRequest::ERRORTYPE_HOOK,
        HeraldWebhookRequest::ERROR_SILENT);
      return;
    }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Inspect the request in the Webhooks UI -- it already has a terminal status, so no further action is needed for that request.
  2. If you need another delivery, fire a fresh request via './bin/herald call-webhook --id <hook> --object <object>'.
  3. Let the duplicate task die: permanent failure removes it from the queue without retries.
Defensive patterns

Strategy: validation

Validate before calling

// In any custom processor, re-check status before acting on a request:
$request = id(new HeraldWebhookRequestQuery())
  ->setViewer($viewer)
  ->withPHIDs(array($request_phid))
  ->executeOne();
if (!$request || $request->getStatus() !== HeraldWebhookRequest::STATUS_QUEUED) {
  return; // already handled elsewhere; skip instead of double-delivering
}

Try / catch

try {
  // process queued webhook request
} catch (PhabricatorWorkerPermanentFailureException $ex) {
  // duplicate/stale task: the request already reached a terminal status
  phlog($ex->getMessage());
}

Prevention

When it happens

Trigger: 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.

Common situations: Queue backlog replayed after a restore; duplicate task insertion during high load; a retried timeout task whose first attempt actually succeeded.

Related errors


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