{"record":{"id":"96469d0f80e45767","repo":"phacility/phabricator","slug":"webhook-request-s-to-s-failed-s-s-96469d","errorCode":null,"errorMessage":"Webhook request (\"%s\", to \"%s\") failed (%s / %s). The request will not be retried.","messagePattern":"Webhook request \\(\"(.+?)\", to \"(.+?)\"\\) failed \\((.+?) / (.+?)\\)\\. The request will not be retried\\.","errorType":"exception","errorClass":"PhabricatorWorkerPermanentFailureException","httpStatus":null,"severity":"error","filePath":"src/applications/herald/worker/HeraldWebhookWorker.php","lineNumber":232,"sourceCode":"        ->setLastRequestResult(HeraldWebhookRequest::RESULT_FAIL);\n\n      if ($should_retry) {\n        $request->save();\n\n        throw new Exception(\n          pht(\n            'Webhook request (\"%s\", to \"%s\") failed (%s / %s). The request '.\n            'will be retried.',\n            $request->getPHID(),\n            $uri,\n            $error_type,\n            $error_code));\n      } else {\n        $request\n          ->setStatus(HeraldWebhookRequest::STATUS_FAILED)\n          ->save();\n\n        throw new PhabricatorWorkerPermanentFailureException(\n          pht(\n            'Webhook request (\"%s\", to \"%s\") failed (%s / %s). The request '.\n            'will not be retried.',\n            $request->getPHID(),\n            $uri,\n            $error_type,\n            $error_code));\n      }\n    } else {\n      $request\n        ->setLastRequestResult(HeraldWebhookRequest::RESULT_OKAY)\n        ->setStatus(HeraldWebhookRequest::STATUS_SENT)\n        ->save();\n    }\n  }\n\n  private function failRequest(\n    HeraldWebhookRequest $request,","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/herald/worker/HeraldWebhookWorker.php#L214-L250","documentation":"The terminal failure branch of webhook delivery: the request failed (timeout or error) and its retry mode is not RETRY_FOREVER, so the worker sets STATUS_FAILED, saves the request with the error details, and throws PhabricatorWorkerPermanentFailureException so the task is dropped after this attempt. The request row keeps the error type/code for inspection in the UI.","triggerScenarios":"The endpoint failed on a hook with a limited or no-retry policy (e.g. a single attempt); the last permitted retry failed; permanent endpoint errors such as 404 or TLS mismatches.","commonSituations":"Misconfigured receiver URL; endpoint moved or dropped the route; hooks configured for limited retries receiving persistent 5xx.","solutions":["Open the failed request in the Webhooks UI and read the recorded error type/code (the %s / %s in the message) to identify HTTP vs timeout failure.","Fix the receiver, then re-fire manually: './bin/herald call-webhook --id <hook> --object <object>'.","For flaky endpoints, switch the hook's retry mode to retry-forever so this becomes the retriable path instead."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before firing, confirm the receiver is healthy so the final attempt is not wasted:\n// (optional) probe the endpoint; then:\n// ./bin/herald call-webhook --id <id> --object <object>","typeGuard":null,"tryCatchPattern":"try {\n  // trigger webhook delivery (worker or call-webhook)\n} catch (PhabricatorWorkerPermanentFailureException $ex) {\n  // delivery exhausted its retry budget: alert, surface request error in UI\n  $this->logPermanentWebhookFailure($ex);\n}","preventionTips":["Read the stored error type/code on the failed request row before re-firing; blind retries just fail again.","Choose retry policies deliberately: retry-forever for recoverable receivers, limited for strict contracts.","Alert on STATUS_FAILED transitions, not just task exceptions, since the row is the source of truth."],"tags":["herald","webhook","phabricator","worker","delivery-failed"],"backgroundTag":"webhook-delivery-failed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}