Skip to content

Webhook retry route hardcodes the event type mis-routes every non-PR dead-lettered event #143

Description

@Siddhartha-singh01

What happened?

POST /api/webhooks/github/retry in src/app/api/webhooks/github/retry/route.ts
re-dispatches a failed webhook event to Inngest with a hardcoded event name:

await inngest.send({
  name: 'github/pull_request',
  data: failedEvent.payload,
});

The failed_webhook_events table has an event_type column (indexed via
failed_webhook_event_type_idx) that exists precisely so retries can be routed to
the correct handler. The retry route ignores it and always sends
github/pull_request.

It works today only by coincidence process-pr-event.ts is currently the only
handler that writes to failed_webhook_events. As soon as any other handler
(installation / issues / review / comment events) dead-letters an event, retrying it
will silently dispatch it to the PR handler. Wrong handler, wrong payload shape and
the route still returns { ok: true }, so the maintainer believes the recovery
succeeded when the event was actually dropped or mis-processed.

This defeats the purpose of the dead-letter retry feature for every event type
except pull_request.

Steps to Reproduce

  1. Insert a row into failed_webhook_events with event_type set to something other
    than github/pull_request (e.g. github/installation).
  2. Call POST /api/webhooks/github/retry with that row's id (as a maintainer).
  3. Observe the Inngest event that gets sent.

Expected Behavior

the event is re-dispatched as github/installation (its original type),
so the process-installation-event handler picks it up.
Actual: it is sent as github/pull_request and handled by process-pr-event.

Where does this occur?

Other

Environment

Not environment-specific this is a code-level event-routing bug in
src/app/api/webhooks/github/retry/route.ts, reproducible on any OS / Node version.
No browser involved backend API route.

Screenshots / Logs

There's no crash log the bug is a silent mis-route, provable by inspection.

The retry route hardcodes the event name (src/app/api/webhooks/github/retry/route.ts):

await inngest.send({
  name: 'github/pull_request',   // hardcoded  ignores failedEvent.event_type
  data: failedEvent.payload,
});

But the failed_webhook_events table stores the original type in an indexed column
(supabase/migrations/0010_add_failed_webhook_events.sql):

event_type TEXT NOT NULL,
...
CREATE INDEX failed_webhook_event_type_idx ON failed_webhook_events (event_type);

So any dead-lettered event whose event_type is not 'github/pull_request' is
re-dispatched to the wrong Inngest handler, and the route still returns { ok: true }.

Metadata

Metadata

Assignees

Labels

GSSOC26GirlScript Summer of Code 2026backendBackend / API / DB relatedbugSomething isn't workinghelp wantedExtra attention is neededlevel:advancedAdvanced level difficulty

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions