mastra-ai/mastra · error

GitHub installation was not found

Error message

GitHub installation ${connection.installationId} was not found

What it means

The connection tied to the repository link references a GitHub App installation (installationId). If storage.installations.get finds no such installation in the org, createWorkspaceFactory throws because token minting for the sandbox requires the installation.

Solutions

  1. Reinstall the GitHub App on the target org/account and re-register the installation in storage
  2. Update the connection's installationId to a valid existing installation
  3. Verify with storage.installations.get({ orgId: session.orgId, id: connection.installationId }) before resolving the session

Example fix

// before
const factory = await createWorkspaceFactory({ session }); // app uninstalled
// after
const installation = await storage.installations.get({ orgId: session.orgId, id: connection.installationId });
if (!installation) {
  await reinstallGithubAppAndRegisterInstallation(); // restores installations row
}
const factory = await createWorkspaceFactory({ session });
Defensive patterns

Strategy: validation

Validate before calling

const conn = await storage.connections.get({ orgId: session.orgId, id: link.connectionId });
if (conn) {
  const inst = await storage.installations.get({ orgId: session.orgId, id: conn.installationId });
  if (!inst) throw new Error('GitHub App installation missing; reinstall before resolving');
}

Type guard

null

Try / catch

try {
  factory = await createWorkspaceFactory({ session, user });
} catch (e) {
  if (e.message.includes('GitHub installation') && e.message.includes('was not found')) {
    // guide user to reinstall the GitHub App, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: The GitHub App installation was uninstalled from the target org/account after the connection was created, or the installation row was removed from storage while its connection remains.

Common situations: An org admin uninstalling the GitHub App, installation revoked due to policy changes, or syncing connections without their installations during migrations.

Related errors


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

Appendix: source

Thrown at mastracode/factory/src/workspace.ts:297

      throw new Error('GitHub and a sandbox callback are required to create a Factory session workspace');
    }
    const createSessionSandboxInstance = sandboxConfig;

    const storage = github.sourceControlStorage;
    const projectRepository = await storage.projectRepositories.get({
      orgId: session.orgId,
      id: session.projectRepositoryId,
    });
    if (!projectRepository) throw new Error(`Repository link ${session.projectRepositoryId} was not found`);
    // The remaining reads only depend on the repository link — issue them in
    // parallel instead of paying four sequential storage round-trips.
    const [connection, repository] = await Promise.all([
      storage.connections.get({ orgId: session.orgId, id: projectRepository.connectionId }),
      storage.repositories.get({ orgId: session.orgId, id: projectRepository.repositoryId }),
    ]);
    if (!connection || !repository) throw new Error(`Repository link ${session.projectRepositoryId} is incomplete`);
    const installation = await storage.installations.get({ orgId: session.orgId, id: connection.installationId });
    if (!installation) throw new Error(`GitHub installation ${connection.installationId} was not found`);
    const repoFullName = repository.slug;

    // Construct (or fetch) the session's memoized sandbox instance.
    // Construction is cheap and side-effect-free by the callback contract —
    // the VM is provisioned on `start()`, which only the materialization
    // pipeline calls. The workdir is never persisted or trusted from storage
    // or client input (the stale-workdir incident class came from reusing
    // `session.sandboxWorkdir` written under a different provider): local
    // sandboxes derive it at construction, remote sandboxes clone into the
    // VM's own home so it resolves lazily at first start.
    // `runSetupOn` references `runSessionSetup`, defined below — it is only
    // invoked during start, long after this closure fully initializes.
    const runSetupOn = (target: unknown, workdir: string) =>
      runSessionSetup(requireExec(target as WorkspaceSandbox), workdir);
    const guardedSetup = createSessionSetupHook(runSetupOn, session.id, repoFullName);
    // Composed start hook: marker-guarded repo setup, then per-start
    // credential install. It runs inside the provider's start lifecycle on
    // EVERY start (create or reconnect) — providers own lazy start

View on GitHub (pinned to 75dd419e61)