{"record":{"id":"2bbc17e3270e93f3","repo":"mastra-ai/mastra","slug":"missing-required-query-param-threadid","errorCode":null,"errorMessage":"Missing required query param: threadId","messagePattern":"Missing required query param: threadId","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/routes/fs.ts","lineNumber":461,"sourceCode":"  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\n  return {\n    workspacePath: session.sessionId,\n    threadId: safeThreadId,\n    files: await filesystem.listFiles({ resourceId: session.sessionId, threadId: safeThreadId }),\n  };\n}\n\ninterface SessionSandboxHandle {\n  sandbox: ExecutableSandbox;\n  filesystem: SandboxFilesystem;\n  workdir: string;\n}","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/routes/fs.ts#L443-L479","documentation":"listSessionFilesystemFiles requires the thread whose captured workspace file listing should be served. It trims the threadId and throws when the result is empty, because a blank threadId would otherwise resolve to a meaningless or wrong session listing.","triggerScenarios":"Calling listSessionFilesystemFiles (or hitting the GET route built by buildFsRoutes) with threadId omitted from the query string, or passing a threadId that is only whitespace.","commonSituations":"Route handlers forwarding query params without validating presence; clients constructing URLs programmatically and dropping the query param; template/interpolation bugs where a variable is undefined so the param serializes as empty.","solutions":["Pass a non-empty threadId query parameter identifying the session thread whose files should be listed.","Validate threadId presence client-side before issuing the request and surface a 400-style message early.","Ensure the route's query parsing actually reads the param (e.g. c.req.query('threadId')) rather than an optional that silently defaults to ''."],"exampleFix":"// before\nfetch(`/api/fs/files?threadId=`);\n// after\nif (!threadId) throw new Error('threadId is required');\nfetch(`/api/fs/files?threadId=${encodeURIComponent(threadId)}`);","handlingStrategy":"validation","validationCode":"function canListSessionFiles(params: { threadId?: string | null }): boolean {\n  return typeof params.threadId === 'string' && params.threadId.trim().length > 0;\n}\nif (!canListSessionFiles(query)) throw new Error('threadId query param is required');","typeGuard":"function hasThreadId(q: Record<string, string | undefined>): q is Record<string, string> & { threadId: string } {\n  return typeof q.threadId === 'string' && q.threadId.trim() !== '';\n}","tryCatchPattern":"try {\n  const listing = await listSessionFilesystemFiles(fs, session, threadId);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('threadId')) {\n    return Response.json({ error: 'threadId query param is required' }, { status: 400 });\n  }\n  throw e;\n}","preventionTips":["Always build request URLs with encodeURIComponent(threadId) from a validated variable.","Add a client-side assertion that threadId is non-empty before fetching.","In route handlers, destructure and validate required query params at the top of the handler."],"tags":["http","validation","missing-parameter"],"backgroundTag":"missing-required-parameter","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}