GitHub webhook failed: delivery and signature troubleshooting
GitHub records each webhook delivery with its request, response, event type, and delivery identifier. Use that delivery record as the starting point for diagnosis.
When a webhook secret is configured, verify X-Hub-Signature-256 against the exact request body using HMAC-SHA256.
Failure patterns
| Symptom | Likely area |
|---|---|
| No request reaches the endpoint | URL, DNS, TLS, firewall, or subscription configuration. |
| HTTP 401 | Missing signature, wrong secret, or body mutation. |
| HTTP 404 | Incorrect route or deployment path. |
| HTTP 5xx | Unhandled application or dependency error. |
| 2xx with no state change | Event routing or business processing failure. |
Verify X-Hub-Signature-256
javascript
import crypto from 'node:crypto';
function verifyGitHub(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const a = Buffer.from(expected, 'utf8');
const b = Buffer.from(signature || '', 'utf8');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}How to diagnose the delivery
- Open the delivery in the repository, organization, or GitHub App webhook settings.
- Record the delivery ID, event name, action, request URL, response status, and response body.
- Find the same request in Hookmetry and compare X-GitHub-Delivery, X-GitHub-Event, X-Hub-Signature-256, and the body.
- If verification fails, confirm the configured secret and raw-body handling.
- If verification passes, trace the delivery ID through event routing and application logs.
- Redeliver only after the handler is safe to process the same delivery again.
Event routing checks
- Branch on X-GitHub-Event and the payload action rather than assuming one payload shape.
- Return 2xx for event types you intentionally ignore after verification.
- Log the delivery ID with each processing attempt.
- Make state changes idempotent before using redelivery.
Verify the fix
A new or safely redelivered GitHub event should receive a 2xx response, pass HMAC verification, appear under one delivery ID in application logs, and produce the expected state change once.