mastra-ai/mastra · error
Repository link was not found
Error message
Repository link ${session.projectRepositoryId} was not found What it means
A Factory session references a project-repository link (projectRepositoryId). If storage.projectRepositories.get returns nothing for that id in the session's org, createWorkspaceFactory throws because it cannot determine which repository the workspace should be built around.
Solutions
- Recreate the repository link (projectRepositories.create) and update the session's projectRepositoryId
- Confirm the link exists in the same org: storage.projectRepositories.get({ orgId: session.orgId, id: session.projectRepositoryId })
- Delete and recreate the session against a valid repository link if the old link is unrecoverable
Example fix
// before
const factory = await createWorkspaceFactory({ session }); // link deleted
// after
const link = await storage.projectRepositories.get({ orgId: session.orgId, id: session.projectRepositoryId });
if (!link) {
const newLink = await storage.projectRepositories.create({ orgId: session.orgId, connectionId, repositoryId });
await storage.sessions.update({ id: session.id, projectRepositoryId: newLink.id });
}
const factory = await createWorkspaceFactory({ session }); Defensive patterns
Strategy: validation
Validate before calling
const link = await storage.projectRepositories.get({ orgId: session.orgId, id: session.projectRepositoryId });
if (!link) throw new Error(`Repository link ${session.projectRepositoryId} missing; recreate it before resolving the session`); Type guard
null
Try / catch
try {
factory = await createWorkspaceFactory({ session, user });
} catch (e) {
if (e.message.includes('Repository link') && e.message.includes('was not found')) {
// recreate link + update session, then retry once
} else throw e;
} Prevention
- Cascade-delete or reassign sessions when removing project-repository links
- Back up and restore projectRepositories rows together with sessions
- Verify link existence in the same org before resolving sessions
When it happens
Trigger: Resolving a session whose projectRepositoryId points to a deleted project-repository link, an id from another org, or a session created against storage that has since been cleared/migrated.
Common situations: Repository link deleted by an admin while a session still references it, restoring sessions from a backup without the linked projectRepositories rows, or cross-environment storage mismatch.
Related errors
- Repository link is incomplete
- Dataset not found
- Dataset not found
- Experiment not found
- Experiment result not found
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/6a06f5ca6f8112ba.
Report an issue: GitHub.
Appendix: source
Thrown at mastracode/factory/src/workspace.ts:288
if (!user?.organizationId || !userId) {
throw new Error(`Factory session ${session.sessionId} was resolved without a caller identity`);
}
// Org-visible sessions open to any member of the owning organization;
// only private sessions stay owner-only. Cross-org access never passes.
if (user.organizationId !== session.orgId || (session.visibility === 'private' && userId !== session.userId)) {
throw new Error(`Factory session ${session.sessionId} is not available to the current user`);
}
if (!sandboxConfig || !github) {
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 theView on GitHub (pinned to 75dd419e61)