phacility/phabricator · error · PhabricatorWorkerPermanentFailureException
Unable to load webhook request ("%s"). It may have been garb
Error message
Unable to load webhook request ("%s"). It may have been garbage collected. What it means
The webhook worker task carries a 'webhookRequestPHID' in its task data; when HeraldWebhookQuery cannot load that row, the task permanently fails with PhabricatorWorkerPermanentFailureException. The most common cause is the request row being garbage collected while the task was still queued, so the work it describes no longer exists.
Source
Thrown at src/applications/herald/worker/HeraldWebhookWorker.php:17
<?php
final class HeraldWebhookWorker
extends PhabricatorWorker {
protected function doWork() {
$viewer = PhabricatorUser::getOmnipotentUser();
$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 thenView on GitHub (pinned to 5720a38cfe)
Solutions
- Treat the permanent failure as expected cleanup: the request is gone, so no delivery is possible; acknowledge/alert rather than retry.
- If delivery still matters, re-fire a fresh request with './bin/herald call-webhook --id <hook> --object <object>'.
- If this recurs, review webhook-request garbage collection retention so live queued requests are not collected.
- Prune stale queued tasks after DB restores so they do not execute against missing rows.
Defensive patterns
Strategy: try-catch
Validate before calling
// When queueing webhook work yourself, only queue for requests that exist:
$request = id(new HeraldWebhookRequestQuery())
->setViewer($viewer)
->withPHIDs(array($request_phid))
->executeOne();
if ($request) {
PhabricatorWorker::scheduleTask(
'HeraldWebhookWorker',
array('webhookRequestPHID' => $request->getPHID()));
} Try / catch
// In daemon/tooling that processes worker results, treat permanent failures as terminal:
try {
$task->executeTask();
} catch (PhabricatorWorkerPermanentFailureException $ex) {
// Request row is gone (e.g. garbage collected); log and move on. Never retry.
phlog($ex->getMessage());
} Prevention
- Keep webhook-request GC retention longer than your worst-case queue backlog.
- After DB restores, prune stale queued tasks before restarting daemons.
- Monitor permanent-failure counts so silently dropped deliveries are visible.
When it happens
Trigger: A queued webhook call task executes after its herald_webhook_request row was garbage collected; worker queue data surviving a database restore that dropped request rows; the request row was deleted manually.
Common situations: Daemon downtime plus GC catching up; restoring a DB backup while the worker queue retains old tasks; aggressive webhook-request retention on a slow queue.
Related errors
- Webhook request ("%s") is not in "%s" status (actual status
- Associated hook ("%s") for webhook request ("%s") is disable
- Unable to load object ("%s") for webhook request ("%s").
- Webhook request ("%s", to "%s") failed (%s / %s). The reques
- Webhook request ("%s", to "%s") failed (%s / %s). The reques
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/adf281f7275325b6.
Report an issue: GitHub.