mastra-ai/mastra · error

Version-control installation not found.

Error message

Version-control installation not found.

What it means

Thrown by PlatformGithubIntegration.getRepositoryAccess when the local installation record referenced by repository.installationId cannot be found in storage. The library stores repositories and their owning GitHub App installations as separate rows; a repository row pointing at a missing installation row means stale or inconsistent linkage data, so no installation token can be minted.

Source

Thrown at mastracode/factory/src/integrations/platform/github/integration.ts:395

              providerMetadata: repository.metadata,
            },
          }),
        ),
      ),
    getRepositoryAccess: async ({ orgId, repositoryId }) => {
      // Every session materialization requests access; reuse a recent grant
      // instead of re-minting through the Platform each time. The TTL keeps
      // a wide margin under GitHub's ~60min installation-token lifetime.
      const cacheKey = `${orgId}:${repositoryId}`;
      const cached = this.#repositoryAccessCache.get(cacheKey);
      if (cached && cached.expiresAt > Date.now()) return cached.access;
      this.#repositoryAccessCache.delete(cacheKey);

      const repository = await this.storage.repositories.get({ orgId, id: repositoryId });
      if (!repository) throw new Error('Version-control repository not found.');
      const cloneUrl = `https://github.com/${repository.slug}.git`;
      const installation = await this.storage.installations.get({ orgId, id: repository.installationId });
      if (!installation) throw new Error('Version-control installation not found.');
      const installationId = parsePositiveInteger(installation.externalId);
      if (installationId === null) throw new Error('GitHub installation id is invalid.');
      const repositoryName = splitRepository(repository.slug).repo;

      try {
        const token = await this.#client.request<{ token: string }>(
          'POST',
          `${API_PREFIX}/github-app/installations/${installationId}/token`,
          { repositories: [repositoryName], permissions: REPOSITORY_TOKEN_PERMISSIONS },
        );
        const access: RepositoryAccess = {
          cloneUrl,
          authorization: { scheme: 'bearer', token: token.token },
        };
        setBounded(this.#repositoryAccessCache, cacheKey, {
          access,
          expiresAt: Date.now() + REPOSITORY_ACCESS_CACHE_TTL_MS,
        });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Re-run the integration's source sync (intake.listSources) so the repository row is relinked to the current installation row
  2. Check storage for the installation row: verify an installation exists with id === repository.installationId in the same org
  3. If the app was reinstalled, update repository.installationId to the new installation's id
  4. Restore the deleted installation row from backup or recreate it via the app-installation webhook

Example fix

// before (stale reference)
await storage.repositories.update({ orgId, id: repositoryId, installationId: OLD_INSTALLATION_ID });
// after (relink to reinstalled app installation)
const installation = await storage.installations.getByExternalId({ orgId, externalId: newGithubInstallationId });
await storage.repositories.update({ orgId, id: repositoryId, installationId: installation.id });
Defensive patterns

Strategy: try-catch

Validate before calling

const repo = await storage.repositories.get({ orgId, id: repositoryId });
if (!repo) throw new Error('repository not found');
const installation = await storage.installations.get({ orgId, id: repo.installationId });
if (!installation) throw new Error(`installation ${repo.installationId} missing for repository ${repositoryId}`);

Try / catch

try {
  const access = await github.getRepositoryAccess({ orgId, repositoryId });
} catch (err) {
  if (err instanceof Error && err.message === 'Version-control installation not found.') {
    await resyncSources(orgId); // relink repository to current installation
  } else throw err;
}

Prevention

When it happens

Trigger: Calling getRepositoryAccess (directly or via session materialization) for a repository whose installationId does not resolve to an installation row in this.storage.installations.get({ orgId, id }).

Common situations: The GitHub App was uninstalled and the installation row was deleted (or a reinstall created a new installation row) while the repository row still references the old installation id; manual DB cleanup or a partial sync removed the installation; cross-org id mismatch.

Related errors


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