{"record":{"id":"66ce8f088e78fd7f","repo":"phacility/phabricator","slug":"webhook-request-s-to-s-failed-s-s","errorCode":null,"errorMessage":"Webhook request (\"%s\", to \"%s\") failed (%s / %s). The request will be retried.","messagePattern":"Webhook request \\(\"(.+?)\", to \"(.+?)\"\\) failed \\((.+?) / (.+?)\\)\\. The request will be retried\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/herald/worker/HeraldWebhookWorker.php","lineNumber":219,"sourceCode":"    }\n    $error_code = $status->getStatusCode();\n\n    $request\n      ->setErrorType($error_type)\n      ->setErrorCode($error_code)\n      ->setLastRequestEpoch(PhabricatorTime::getNow());\n\n    $retry_forever = HeraldWebhookRequest::RETRY_FOREVER;\n    if ($status->isTimeout() || $status->isError()) {\n      $should_retry = ($request->getRetryMode() === $retry_forever);\n\n      $request\n        ->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,","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/herald/worker/HeraldWebhookWorker.php#L201-L237","documentation":"After a webhook call times out or errors, if the request's retry mode is RETRY_FOREVER the worker records RESULT_FAIL, saves the request, and throws a plain Exception -- which makes the task daemon retry it later with backoff. This is the designed failure path for receivers that are temporarily down; it is transient by construction.","triggerScenarios":"The receiver returned 5xx, refused the connection, or timed out, and the hook is configured to retry forever; each retry that still fails rethrows this exception.","commonSituations":"Target service restarting or deploying; slow endpoint exceeding the HTTP timeout; network blips between Phabricator and the receiver.","solutions":["Fix the receiving endpoint -- check its logs for the failing request from the Phabricator host.","Verify the network path (DNS, firewall, TLS) from the Phabricator server, not from your workstation.","No Phabricator-side action is required: once the endpoint recovers, the retries will succeed and the request flips to SENT.","If the retry flood is unwanted, change the hook's retry policy away from retry-forever."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Probing a receiver before enabling retry-forever:\nPhabricatorEnv::requireValidRemoteURIForFetch($uri, array('http', 'https'));\n// then a cheap GET/HEAD from the Phabricator host confirms reachability","typeGuard":null,"tryCatchPattern":"// The worker already retries with backoff; in adjacent tooling mirror that:\ntry {\n  deliver();\n} catch (Exception $ex) {\n  // transient: schedule retry with exponential backoff, cap concurrency\n  scheduleRetry($ex);\n}","preventionTips":["Set retry-forever on hooks pointing at services with occasional deploys; use limited retries for strict ones.","Watch request RESULT_FAIL counts as an early signal that a receiver is down.","Keep receiver timeouts shorter than the worker task lease so retries are not duplicated."],"tags":["herald","webhook","phabricator","worker","retry","transient"],"backgroundTag":"webhook-delivery-failed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}