mastra-ai/mastra · error · Error

GitHub integration is required to load webhook…

Error message

GitHub integration is required to load webhook subscriptions.

What it means

dispatchGithubWebhook lists PR subscriptions via an injectable listSubscriptions dependency; when no override is supplied it falls back to listPullRequestSubscriptionsForWebhook, which requires dependencies.github.integrationStorage. If dependencies.github is absent, there is no storage to read subscriptions from, so the lazily-built closure throws with a clear message instead of an opaque undefined-access error.

Solutions

  1. Pass dependencies.github when constructing/calling dispatchGithubWebhook so integrationStorage is available
  2. Supply a custom dependencies.listSubscriptions override if running without the full GitHub integration
  3. Make dependencies.github a required constructor/parameter type so TypeScript catches the omission at compile time
  4. Add an upfront guard at the top of dispatchGithubWebhook that fails fast with a configuration error listing the missing dependency

Example fix

// before
await dispatchGithubWebhook(notification, { controller, sessions });
// after
await dispatchGithubWebhook(notification, {
  controller,
  sessions,
  github: { integrationStorage, sourceControlStorage },
});
Defensive patterns

Strategy: validation

Validate before calling

type WebhookDeps = { github?: GithubWebhookDispatchIntegration; listSubscriptions?: ... };
function assertGithubDeps(deps: WebhookDeps): asserts deps is WebhookDeps & { github: GithubWebhookDispatchIntegration } {
  if (!deps.github && !deps.listSubscriptions) {
    throw new Error('dispatchGithubWebhook requires dependencies.github or a listSubscriptions override.');
  }
}

Type guard

function canListSubscriptions(deps: { github?: unknown; listSubscriptions?: unknown }): boolean {
  return typeof deps.listSubscriptions === '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 load webhook subscriptions')) {
    logger.error('Webhook dispatcher misconfigured: pass dependencies.github');
    return { delivered: 0, failed: 0, skipped: 0 };
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling dispatchGithubWebhook without providing dependencies.github (or a custom dependencies.listSubscriptions) when a pull-request notification needs subscriptions listed.

Common situations: Wiring the webhook dispatcher in a new entry point (server route, queue consumer) and forgetting to pass the GitHub integration dependency; test harness constructs partial dependencies; a refactor made the github dependency optional in the type but required at runtime.

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/e96686e1822c062f. Report an issue: GitHub.

Appendix: source

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

  const notification = classifyGithubWebhook(parsed);
  if (!notification) return { delivered: 0, failed: 0, skipped: 0, ignored: true };
  const isAuthorizedSender =
    dependencies.isAuthorizedSender ??
    ((n: GithubWebhookNotification) => isAuthorizedGithubSender(n, dependencies.github));
  if (!(await isAuthorizedSender(notification))) {
    dependencies.onSenderRejected?.(notification);
    return { delivered: 0, failed: 0, skipped: 0, ignored: true };
  }

  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) {

View on GitHub (pinned to 75dd419e61)