mastra-ai/mastra · error
Factory session not found
Error message
Factory session not found
What it means
Thrown by resolveSourceSession when the source-control storage has no session row for request.sessionId, or the stored session's orgId/userId do not match the request's orgId/userId. This is a tenant-scoped lookup: the session must exist AND belong to the exact org and acting user in the request, otherwise the start is rejected to avoid operating on another tenant's session.
Solutions
- Confirm request.sessionId is a real factory session ID in the same storage backend (query storage.sessions.getBySessionId directly to check).
- Ensure request.orgId and request.userId exactly match the orgId/userId recorded on the session row; use the original creator's credentials or pass the matching user context.
- If the session was deleted or belongs to another environment, create a new factory session instead of replaying the old ID.
- Check you are pointed at the correct storage/database (dev vs prod) for this org.
Example fix
// before
await factory.prepare({ sessionId: 'sess_123', orgId: currentOrgId, userId: someOtherUserId });
// after: use the owning org and user recorded on the session
const stored = await storage.sessions.getBySessionId('sess_123');
await factory.prepare({ sessionId: 'sess_123', orgId: stored.orgId, userId: stored.userId }); Defensive patterns
Strategy: try-catch
Validate before calling
const session = await storage.sessions.getBySessionId(request.sessionId);
if (!session) throw new Error(`Session ${request.sessionId} does not exist in this storage backend.`);
if (session.orgId !== request.orgId || session.userId !== request.userId) {
throw new Error(`Session ${request.sessionId} belongs to org=${session.orgId}/user=${session.userId}.`);
} Type guard
function sessionBelongsToRequest(session: FactorySession | undefined, req: FactoryStartRequest): session is FactorySession {
return !!session && session.orgId === req.orgId && session.userId === req.userId;
} Try / catch
try {
const prepared = await coordinator.prepare(request);
} catch (err) {
if (err instanceof Error && err.message === 'Factory session not found') {
console.error(`No session ${request.sessionId} for org=${request.orgId}/user=${request.userId}; verify the ID and credentials.`);
}
throw err;
} Prevention
- Persist and reuse the full session record (ID + orgId + userId) together, never just the ID.
- Check you are connected to the same environment/storage where the session was created.
- Use the original creator's user context when replaying sessions.
When it happens
Trigger: Calling factory start (prepare and its wrappers) with a sessionId that (a) does not exist in source-control storage (wrong/typo'd ID, session purged, wrong storage backend), (b) exists but was created under a different orgId, or (c) exists under the right org but a different userId than request.userId.
Common situations: Copying a sessionId between environments (staging vs prod) or between orgs; replaying a session from a different user account than the one that created it; storage not migrated/seeded so the session row is missing; using a thread ID instead of the factory session ID.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Project repository not found for this organization.
- Access denied: unable to verify message ownership
- Agent with id not found
- DATASET_ITEM_NOT_FOUND
- DATASET_NOT_FOUND
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/aa5bbefcc7013919.
Report an issue: GitHub.
Appendix: source
Thrown at mastracode/factory/src/rules/start-coordinator.ts:89
const skills = session.getWorkspace()?.skills;
await skills?.maybeRefresh();
const skill = await skills?.get(invocation.skillName);
if (!skill || skill['user-invocable'] === false) {
throw new Error(`Skill not found: ${invocation.skillName}.`);
}
const args = invocation.arguments.trim();
const content = `${formatSkillActivation(skill)}${args ? `\n\nARGUMENTS: ${args}` : ''}`.trim();
return `<skill name="${skill.name}">\n${escapeSkillBoundary(content)}\n</skill>`;
}
async function resolveSourceSession(
storage: SourceControlStorageHandle,
request: FactoryStartRequest,
): Promise<SourceControlSession> {
const session = await storage.sessions.getBySessionId(request.sessionId);
if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {
throw new Error('Factory session not found');
}
const projectRepository = await storage.projectRepositories.get({
orgId: request.orgId,
id: session.projectRepositoryId,
});
if (!projectRepository) throw new Error('Factory session repository not found');
const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });
if (!connection || connection.factoryProjectId !== request.factoryProjectId) {
throw new Error('Factory session does not belong to this project');
}
return session;
}
async function configureThread(session: FactorySession, request: FactoryStartRequest): Promise<string> {
const threadId = session.thread.requireId();
await session.thread.rename({ title: request.threadTitle });
const settings = { ...(request.threadTags ?? {}), factorySessionId: request.sessionId };
await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));View on GitHub (pinned to 75dd419e61)