mastra-ai/mastra · error · HTTPException
Both threadId or resourceId must be provided
Error message
Both threadId or resourceId must be provided
What it means
Thrown by the deprecated POST /agents/:agentId/generate-legacy route handler when exactly one of threadId/resourceId is provided. Memory-scoped generation requires both together: threadId identifies the conversation thread and resourceId identifies its owning resource, so a lone value is rejected with 400.
Source
Thrown at packages/server/src/server/handlers/agents.ts:1508
requestContext,
});
// UI Frameworks may send "client tools" in the body,
// but it interferes with llm providers tool handling, so we remove them
sanitizeBody(params, ['tools', 'actor']);
const { messages, resourceId, resourceid, threadId, ...rest } = params;
// Use resourceId if provided, fall back to resourceid (deprecated)
const clientResourceId = resourceId ?? resourceid;
// Authorization: context values take precedence over client-provided values
const effectiveResourceId = getEffectiveResourceId(requestContext, clientResourceId);
const effectiveThreadId = getEffectiveThreadId(requestContext, threadId);
validateBody({ messages });
if ((effectiveThreadId && !effectiveResourceId) || (!effectiveThreadId && effectiveResourceId)) {
throw new HTTPException(400, { message: 'Both threadId or resourceId must be provided' });
}
// Validate thread ownership if accessing an existing thread
if (effectiveThreadId) {
const memory = await agent.getMemory({ requestContext });
if (memory) {
const thread = await memory.getThreadById({ threadId: effectiveThreadId });
if (thread) {
await enforceThreadAccess({
mastra,
requestContext,
threadId: effectiveThreadId,
thread,
effectiveResourceId,
permission: MastraFGAPermissions.MEMORY_WRITE,
});
}
}View on GitHub (pinned to 75dd419e61)
Solutions
- Send both threadId and resourceId together in the request body (or supply the missing half via requestContext)
- If you don't need memory, omit both fields and call without thread persistence
- Migrate off the deprecated generate-legacy route to /agents/:agentId/generate with matching current parameter handling
Example fix
// before
await client.generate({ threadId: 'thread-1' }); // resourceId missing
// after
await client.generate({ threadId: 'thread-1', resourceId: 'user-42' }); Defensive patterns
Strategy: validation
Validate before calling
function validateMemoryParams(p: { threadId?: string; resourceId?: string }): void {
const hasThread = Boolean(p.threadId);
const hasResource = Boolean(p.resourceId);
if (hasThread !== hasResource) {
throw new Error('threadId and resourceId must be provided together');
}
} Type guard
function hasCompleteMemoryPair(p: { threadId?: string; resourceId?: string }): p is { threadId: string; resourceId: string } {
return typeof p.threadId === 'string' && p.threadId.length > 0 &&
typeof p.resourceId === 'string' && p.resourceId.length > 0;
} Try / catch
try {
await client.generateLegacy({ messages, threadId });
} catch (e) {
if (isHttpException(e, 400) && String(e.message).includes('threadId or resourceId')) {
// add the missing half or drop both
}
} Prevention
- Always pass threadId and resourceId as a pair from a shared memory-context object
- When relying on requestContext-injected values, verify both halves resolve before the call
- Migrate off generate-legacy to the current generate route with pair validation in the client SDK
When it happens
Trigger: Calling generate-legacy with threadId but no resourceId (or vice versa) in the body — remembering that requestContext can supply the effective value, so a body resourceId paired with a threadId-only requestContext (or the reverse) also triggers it.
Common situations: Older clients that only sent threadId; code migrated from an API where resourceId was optional; server middleware injecting resourceId via requestContext while the client still sends only threadId, leaving the other half unset.
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
- messageIds is required
- conversation_id requires the target agent to have memory con
- ${errorMessage}
- MastraClient.deleteThread() requires exactly one of agentId
- bad request: ${responseText}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7127cf8db3c18e24.
Report an issue: GitHub.