mastra-ai/mastra · error

Missing required query param: threadId

Error message

Missing required query param: threadId

What it means

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.

Source

Thrown at mastracode/factory/src/routes/fs.ts:461

  const session = await deps.sessions.getBySessionId(workspacePath);
  if (!session) return null;
  if (deps.auth.enabled()) {
    await deps.auth.ensureUser(c);
    const tenant = deps.auth.tenant(c);
    if (!tenant || tenant.orgId !== session.orgId || tenant.userId !== session.userId) {
      throw new Error('Session is not available to the current user');
    }
  }
  return session;
}

export async function listSessionFilesystemFiles(
  filesystem: Pick<FilesystemStorage, 'listFiles'>,
  session: SourceControlSession,
  threadId: string,
): Promise<WorkspaceFilesListing> {
  const safeThreadId = threadId.trim();
  if (!safeThreadId) throw new Error('Missing required query param: threadId');

  // The turn-end capture no longer gates agent_end, so a reader refetching on
  // run completion could otherwise race it and serve the previous turn's
  // listing. Await the in-flight capture (bounded) before reading.
  await waitForPendingFilesystemCapture(session.sessionId);

  return {
    workspacePath: session.sessionId,
    threadId: safeThreadId,
    files: await filesystem.listFiles({ resourceId: session.sessionId, threadId: safeThreadId }),
  };
}

interface SessionSandboxHandle {
  sandbox: ExecutableSandbox;
  filesystem: SandboxFilesystem;
  workdir: string;
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass a non-empty threadId query parameter identifying the session thread whose files should be listed.
  2. Validate threadId presence client-side before issuing the request and surface a 400-style message early.
  3. Ensure the route's query parsing actually reads the param (e.g. c.req.query('threadId')) rather than an optional that silently defaults to ''.

Example fix

// before
fetch(`/api/fs/files?threadId=`);
// after
if (!threadId) throw new Error('threadId is required');
fetch(`/api/fs/files?threadId=${encodeURIComponent(threadId)}`);
Defensive patterns

Strategy: validation

Validate before calling

function canListSessionFiles(params: { threadId?: string | null }): boolean {
  return typeof params.threadId === 'string' && params.threadId.trim().length > 0;
}
if (!canListSessionFiles(query)) throw new Error('threadId query param is required');

Type guard

function hasThreadId(q: Record<string, string | undefined>): q is Record<string, string> & { threadId: string } {
  return typeof q.threadId === 'string' && q.threadId.trim() !== '';
}

Try / catch

try {
  const listing = await listSessionFilesystemFiles(fs, session, threadId);
} catch (e) {
  if (e instanceof Error && e.message.includes('threadId')) {
    return Response.json({ error: 'threadId query param is required' }, { status: 400 });
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/2bbc17e3270e93f3. Report an issue: GitHub.