mastra-ai/mastra · error · Error

GitHub integration is required to retire webhook subscriptio

Error message

GitHub integration is required to retire webhook subscriptions.

What it means

The retireSubscription dependency in dispatchGithubWebhook defaults to retirePullRequestSubscription, which writes through dependencies.github.integrationStorage. When the GitHub integration dependency is not provided and no custom retireSubscription override is injected, the closure throws so closed/merged PR events cannot silently leave subscriptions unretired.

Source

Thrown at mastracode/factory/src/integrations/github/webhook.ts:541

  const target = {
    installationExternalId: notification.metadata.installationId.toString(),
    repositoryExternalId: notification.metadata.repositoryId.toString(),
    changeRequestId: notification.metadata.pullRequestNumber.toString(),
  };
  const listSubscriptions =
    dependencies.listSubscriptions ??
    ((subscriptionTarget: GithubWebhookPullRequestTarget, options?: { includeTerminal?: boolean }) => {
      if (!dependencies.github) throw new Error('GitHub integration is required to load webhook subscriptions.');
      return listPullRequestSubscriptionsForWebhook(
        subscriptionTarget,
        options,
        dependencies.github.integrationStorage,
      );
    });
  const retireSubscription =
    dependencies.retireSubscription ??
    ((id: string, status: 'open' | 'closed' | 'merged') => {
      if (!dependencies.github) throw new Error('GitHub integration is required to retire webhook subscriptions.');
      return retirePullRequestSubscription(id, status, dependencies.github.integrationStorage);
    });
  const subscriptions = await listSubscriptions(target, { includeTerminal: notification.action === 'reopened' });
  let delivered = 0;
  let failed = 0;
  let skipped = 0;

  for (const subscription of subscriptions) {
    try {
      const session = await resolveSubscriptionSession(dependencies.controller, subscription, dependencies.github);
      // No session means this deployment does not hold the subscribed thread.
      // That is not a delivery failure, so it must not be retried or counted as
      // one; the subscription is left untouched because the thread may exist
      // wherever the subscription was created.
      if (!session) {
        skipped += 1;
        dependencies.onTargetSkipped?.(subscription);
        continue;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass dependencies.github to dispatchGithubWebhook so retirement can write to integrationStorage
  2. Provide a custom dependencies.retireSubscription override when operating without the full integration
  3. Require dependencies.github in the type signature so omissions are caught at compile time
  4. Add an early validation in dispatchGithubWebhook that either github or both list/retire overrides exist

Example fix

// before
await dispatchGithubWebhook(prNotification, { controller });
// after
await dispatchGithubWebhook(prNotification, {
  controller,
  github: { integrationStorage },
  retireSubscription: (id, status) => retirePullRequestSubscription(id, status, integrationStorage),
});
Defensive patterns

Strategy: validation

Validate before calling

if (!dependencies.github && !dependencies.retireSubscription) {
  throw new Error('dispatchGithubWebhook requires dependencies.github or a retireSubscription override.');
}

Type guard

function canRetireSubscriptions(deps: { github?: unknown; retireSubscription?: unknown }): boolean {
  return typeof deps.retireSubscription === 'function' ||
    (typeof deps.github === 'object' && deps.github !== null);
}

Try / catch

try {
  await dispatchGithubWebhook(notification, deps);
} catch (err) {
  if ((err as Error).message.includes('required to retire webhook subscriptions')) {
    logger.error('Cannot retire PR subscriptions: GitHub integration missing from dispatcher deps');
    return { delivered: 0, failed: 0, skipped: 0 };
  }
  throw err;
}

Prevention

When it happens

Trigger: A PR 'closed' or 'merged' webhook dispatches and dispatchGithubWebhook needs to retire matching subscriptions, but dependencies.github is undefined and no custom dependencies.retireSubscription was supplied.

Common situations: Same wiring omission as the listSubscriptions sibling error: entry point constructed without the GitHub integration; tests with partial dependencies that pass listSubscriptions but exercise the retire path; refactors that made the dependency optional without updating all call sites.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/83270e071bca5e81. Report an issue: GitHub.