mastra-ai/mastra · error

GitHub installation id is invalid.

Error message

GitHub installation id is invalid.

What it means

Thrown by PlatformGithubIntegration.getRepositoryAccess when the stored installation's externalId is not a positive integer string. The externalId holds GitHub's numeric installation id; if it is missing, empty, or malformed (e.g. 'unknown', '0', whitespace), the code cannot build the token-minting URL and fails fast before calling the Platform API.

Source

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

          }),
        ),
      ),
    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,
        });
        return access;
      } catch (err) {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Inspect the installation row and set externalId to the numeric GitHub App installation id (digits only, > 0)
  2. Get the correct id from GitHub (Settings > Applications > Installed GitHub Apps, or the installation webhook payload) and update the row
  3. Re-sync sources via intake.listSources so the integration rewrites installation rows from the Platform
  4. Add a pre-insertion validation that externalId matches /^\d+$/

Example fix

// before
await storage.installations.create({ orgId, externalId: 'app-installation-test' });
// after
await storage.installations.create({ orgId, externalId: '12345678' }); // numeric GitHub installation id
Defensive patterns

Strategy: validation

Validate before calling

function hasValidExternalId(i: { externalId: string } | undefined): i is { externalId: string } & { externalId: `${number}` } {
  return !!i && /^\d+$/.test(i.externalId) && Number(i.externalId) > 0;
}

Type guard

function isValidInstallationId(value: string): boolean {
  return /^\d+$/.test(value) && Number(value) > 0;
}

Prevention

When it happens

Trigger: Calling getRepositoryAccess for a repository whose linked installation row has installation.externalId that fails parsePositiveInteger (non-digit characters, empty string, zero-padded/negative value).

Common situations: Manual insertion of the installation row with a placeholder externalId; a sync bug that wrote the account login instead of the numeric GitHub installation id; schema migration left externalId null or empty; importing fixtures with fake ids like 'test-installation'.

Related errors


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