{"record":{"id":"371156a8e4170dfb","repo":"mastra-ai/mastra","slug":"github-installation-id-is-invalid-371156","errorCode":null,"errorMessage":"GitHub installation id is invalid.","messagePattern":"GitHub installation id is invalid\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/platform/github/integration.ts","lineNumber":397,"sourceCode":"          }),\n        ),\n      ),\n    getRepositoryAccess: async ({ orgId, repositoryId }) => {\n      // Every session materialization requests access; reuse a recent grant\n      // instead of re-minting through the Platform each time. The TTL keeps\n      // a wide margin under GitHub's ~60min installation-token lifetime.\n      const cacheKey = `${orgId}:${repositoryId}`;\n      const cached = this.#repositoryAccessCache.get(cacheKey);\n      if (cached && cached.expiresAt > Date.now()) return cached.access;\n      this.#repositoryAccessCache.delete(cacheKey);\n\n      const repository = await this.storage.repositories.get({ orgId, id: repositoryId });\n      if (!repository) throw new Error('Version-control repository not found.');\n      const cloneUrl = `https://github.com/${repository.slug}.git`;\n      const installation = await this.storage.installations.get({ orgId, id: repository.installationId });\n      if (!installation) throw new Error('Version-control installation not found.');\n      const installationId = parsePositiveInteger(installation.externalId);\n      if (installationId === null) throw new Error('GitHub installation id is invalid.');\n      const repositoryName = splitRepository(repository.slug).repo;\n\n      try {\n        const token = await this.#client.request<{ token: string }>(\n          'POST',\n          `${API_PREFIX}/github-app/installations/${installationId}/token`,\n          { repositories: [repositoryName], permissions: REPOSITORY_TOKEN_PERMISSIONS },\n        );\n        const access: RepositoryAccess = {\n          cloneUrl,\n          authorization: { scheme: 'bearer', token: token.token },\n        };\n        setBounded(this.#repositoryAccessCache, cacheKey, {\n          access,\n          expiresAt: Date.now() + REPOSITORY_ACCESS_CACHE_TTL_MS,\n        });\n        return access;\n      } catch (err) {","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/platform/github/integration.ts#L379-L415","documentation":"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.","triggerScenarios":"Calling getRepositoryAccess for a repository whose linked installation row has installation.externalId that fails parsePositiveInteger (non-digit characters, empty string, zero-padded/negative value).","commonSituations":"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'.","solutions":["Inspect the installation row and set externalId to the numeric GitHub App installation id (digits only, > 0)","Get the correct id from GitHub (Settings > Applications > Installed GitHub Apps, or the installation webhook payload) and update the row","Re-sync sources via intake.listSources so the integration rewrites installation rows from the Platform","Add a pre-insertion validation that externalId matches /^\\d+$/"],"exampleFix":"// before\nawait storage.installations.create({ orgId, externalId: 'app-installation-test' });\n// after\nawait storage.installations.create({ orgId, externalId: '12345678' }); // numeric GitHub installation id","handlingStrategy":"validation","validationCode":"function hasValidExternalId(i: { externalId: string } | undefined): i is { externalId: string } & { externalId: `${number}` } {\n  return !!i && /^\\d+$/.test(i.externalId) && Number(i.externalId) > 0;\n}","typeGuard":"function isValidInstallationId(value: string): boolean {\n  return /^\\d+$/.test(value) && Number(value) > 0;\n}","tryCatchPattern":null,"preventionTips":["Validate externalId matches /^\\d+$/ before inserting installation rows","Always write the numeric GitHub installation id from the webhook payload, never a label","Add a schema constraint or check on the installations.externalId column","Re-sync installations from the Platform after manual DB edits"],"tags":["github","installation","validation","data-integrity"],"backgroundTag":"invalid-external-id","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}