{"record":{"id":"e2b04c7bec097e75","repo":"mastra-ai/mastra","slug":"factory-session-does-not-belong-to-this-project","errorCode":null,"errorMessage":"Factory session does not belong to this project","messagePattern":"Factory session does not belong to this project","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/start-coordinator.ts","lineNumber":98,"sourceCode":"  return `<skill name=\"${skill.name}\">\\n${escapeSkillBoundary(content)}\\n</skill>`;\n}\n\nasync function resolveSourceSession(\n  storage: SourceControlStorageHandle,\n  request: FactoryStartRequest,\n): Promise<SourceControlSession> {\n  const session = await storage.sessions.getBySessionId(request.sessionId);\n  if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {\n    throw new Error('Factory session not found');\n  }\n  const projectRepository = await storage.projectRepositories.get({\n    orgId: request.orgId,\n    id: session.projectRepositoryId,\n  });\n  if (!projectRepository) throw new Error('Factory session repository not found');\n  const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });\n  if (!connection || connection.factoryProjectId !== request.factoryProjectId) {\n    throw new Error('Factory session does not belong to this project');\n  }\n  return session;\n}\n\nasync function configureThread(session: FactorySession, request: FactoryStartRequest): Promise<string> {\n  const threadId = session.thread.requireId();\n  await session.thread.rename({ title: request.threadTitle });\n  const settings = { ...(request.threadTags ?? {}), factorySessionId: request.sessionId };\n  await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));\n  return threadId;\n}\n\nexport class FactoryStartCoordinator {\n  readonly #controller: FactoryController;\n  readonly #storage: WorkItemsStorage;\n  readonly #transitionService?: Pick<FactoryTransitionService, 'transition'>;\n  readonly #sourceControl?: SourceControlStorageHandle;\n  readonly #memorySettings?: MemorySettingsStorage;","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/start-coordinator.ts#L80-L116","documentation":"Thrown by resolveSourceSession as the final ownership check: the session and its project repository exist, but the connection backing that repository is missing or its factoryProjectId does not match request.factoryProjectId. The library refuses to start a session against a factory project it is not actually bound to, preventing cross-project access.","triggerScenarios":"Calling factory start with a factoryProjectId that differs from the one on the repository's connection (wrong project passed in the request), the repository's connection was deleted (connection lookup returns undefined), or the repo was re-pointed to a different factory project after the session was created.","commonSituations":"Automation passing a hardcoded/default factoryProjectId while the session lives under another project; a project was deleted and recreated (new factoryProjectId) but old connections/sessions still point at the old ID; moving a repo between factory projects without updating sessions.","solutions":["Pass the correct factoryProjectId — the one on the connection that owns the session's repository (storage.connections.get({orgId, id: repo.connectionId}).factoryProjectId).","If the connection is missing, reconnect the repository (recreate the connection) so projectRepository.connectionId resolves.","If the project was recreated with a new ID, re-bind the repository's connection to the new factoryProjectId or create a new session under the new project.","Verify no environment/config mismatch: the request's factoryProjectId should come from the same environment as the storage data."],"exampleFix":"// before: wrong project in request\nawait factory.prepare({ sessionId, orgId, userId, factoryProjectId: 'proj_default' });\n\n// after: resolve the project from the session's repo connection\nconst session = await storage.sessions.getBySessionId(sessionId);\nconst repo = await storage.projectRepositories.get({ orgId, id: session.projectRepositoryId });\nconst conn = await storage.connections.get({ orgId, id: repo.connectionId });\nawait factory.prepare({ sessionId, orgId, userId, factoryProjectId: conn.factoryProjectId });","handlingStrategy":"validation","validationCode":"const session = await storage.sessions.getBySessionId(request.sessionId);\nconst repo = session && await storage.projectRepositories.get({ orgId: request.orgId, id: session.projectRepositoryId });\nconst conn = repo && await storage.connections.get({ orgId: request.orgId, id: repo.connectionId });\nif (!conn) throw new Error('Repository connection is missing; reconnect the repository.');\nif (conn.factoryProjectId !== request.factoryProjectId) {\n  throw new Error(`Expected factoryProjectId ${conn.factoryProjectId}, got ${request.factoryProjectId}.`);\n}","typeGuard":"function matchesProject(conn: Connection | undefined, req: FactoryStartRequest): conn is Connection {\n  return !!conn && conn.factoryProjectId === req.factoryProjectId;\n}","tryCatchPattern":"try {\n  const prepared = await coordinator.prepare(request);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Factory session does not belong to this project') {\n    console.error('factoryProjectId in the request does not match the session’s repository connection; resolve it from the connection.');\n  }\n  throw err;\n}","preventionTips":["Always derive factoryProjectId from the session’s repository connection rather than hardcoding it.","When recreating a deleted project, re-bind connections and open new sessions for the new project ID.","Log orgId/projectId/sessionId together in automation to spot cross-project mismatches early."],"tags":["project","ownership","authorization","mismatch"],"backgroundTag":"ownership-mismatch","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}