{"record":{"id":"2876e5d84198e345","repo":"mastra-ai/mastra","slug":"session-is-not-available-to-the-current-user","errorCode":null,"errorMessage":"Session is not available to the current user","messagePattern":"Session is not available to the current user","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/routes/fs.ts","lineNumber":449,"sourceCode":"/**\n * Resolve a `workspacePath` query param as a Factory session id. Returns the\n * session when one exists and the caller owns it, `null` when no session\n * matches (the caller should fall back to local-path handling), and throws\n * when a session exists but belongs to another tenant.\n */\nasync function resolveAuthorizedSession(\n  c: Context,\n  deps: SessionFsDeps | undefined,\n  workspacePath: string,\n): Promise<SourceControlSession | null> {\n  if (!deps) return null;\n  const session = await deps.sessions.getBySessionId(workspacePath);\n  if (!session) return null;\n  if (deps.auth.enabled()) {\n    await deps.auth.ensureUser(c);\n    const tenant = deps.auth.tenant(c);\n    if (!tenant || tenant.orgId !== session.orgId || tenant.userId !== session.userId) {\n      throw new Error('Session is not available to the current user');\n    }\n  }\n  return session;\n}\n\nexport async function listSessionFilesystemFiles(\n  filesystem: Pick<FilesystemStorage, 'listFiles'>,\n  session: SourceControlSession,\n  threadId: string,\n): Promise<WorkspaceFilesListing> {\n  const safeThreadId = threadId.trim();\n  if (!safeThreadId) throw new Error('Missing required query param: threadId');\n\n  // The turn-end capture no longer gates agent_end, so a reader refetching on\n  // run completion could otherwise race it and serve the previous turn's\n  // listing. Await the in-flight capture (bounded) before reading.\n  await waitForPendingFilesystemCapture(session.sessionId);\n","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/routes/fs.ts#L431-L467","documentation":"resolveAuthorizedSession maps a workspacePath that is a Factory session id to a session record. When auth is enabled, after confirming the session exists it compares the caller's tenant (orgId/userId from deps.auth) with the session owner and throws 'Session is not available to the current user' on mismatch. This is a tenancy/ownership guard: a session exists but belongs to a different user or organization, so it must not be visible to the caller (distinct from returning null, which means no such session at all).","triggerScenarios":"Requesting session filesystem routes with workspacePath set to another user's session id while authenticated; calling with an unauthenticated/no-tenant context (tenant() returns null) while the session exists; tokens issued for a different org than the one owning the session; stale credentials after the session was transferred or the user's org changed.","commonSituations":"Sharing a Studio/Factory URL containing a session id with a teammate; using a personal-access token from the wrong organization; a reverse proxy stripping auth headers so tenant() is null; multi-tenant environments where the client cached an old session id.","solutions":["Confirm you are authenticated as the user who owns the session (orgId and userId must both match) — log in as that user or request access.","Check the auth token/credentials: ensure they are issued for the same organization as the session.","Verify the session id in workspacePath is yours (list your sessions rather than copying an id from a shared URL).","If auth headers are being stripped by a proxy, fix proxy configuration so deps.auth.tenant(c) receives a valid tenant."],"exampleFix":"// before: shared link to another user's session\nGET /fs?workspacePath=<someone-elses-session-id>  // → 403-ish 'Session is not available to the current user'\n// after: use your own session id\nGET /fs?workspacePath=<your-own-session-id>","handlingStrategy":"try-catch","validationCode":"// client-side: only request sessions returned by your own session list\nconst mySessions = await fetch('/sessions', { headers: authHeaders }).then(r => r.json());\nconst owns = mySessions.some(s => s.sessionId === workspacePath);\nif (!owns) throw new Error('refusing request: session not owned by current user');","typeGuard":"function isOwnSession(\n  session: { orgId: string; userId: string },\n  tenant: { orgId: string; userId: string } | null,\n): boolean {\n  return tenant !== null && tenant.orgId === session.orgId && tenant.userId === session.userId;\n}","tryCatchPattern":"try {\n  const files = await fetchSessionFiles(workspacePath, threadId);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Session is not available to the current user') {\n    // treat as 403: re-authenticate with the owning org's credentials or hide the link\n    return { status: 'forbidden' };\n  }\n  throw e;\n}","preventionTips":["Never share or hardcode session ids across users/orgs; fetch session lists per authenticated user.","Ensure auth headers survive proxies so deps.auth.tenant(c) is populated.","Re-authenticate after org changes; stale tokens cause tenant mismatch.","Distinguish null (no such session → local-path fallback) from this throw (exists but not yours) in client logic."],"tags":["auth","authorization","multi-tenancy","access-control"],"backgroundTag":"session-not-owned-by-user","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}