mastra-ai/mastra · error · MastraError
OBSERVATIONAL_MEMORY_THREAD_ID_REQUIRED
OBSERVATIONAL_MEMORY_THREAD_ID_REQUIRED
Error message
OBSERVATIONAL_MEMORY_THREAD_ID_REQUIRED: ObservationalMemory (scope: 'thread') requires a threadId, but none was found in RequestContext or MessageList. Ensure the agent is configured with Memory and a valid threadId is provided.
What it means
In `scope: 'thread'` mode, ObservationalMemory keys all its state per thread. Without a threadId it would silently fall back to a resource-keyed record, which deadlocks when multiple threads share one resourceId. The processor therefore throws a MastraError (OBSERVATIONAL_MEMORY_THREAD_ID_REQUIRED, USER category) when it cannot find a threadId in either the RequestContext or the MessageList.
Source
Thrown at packages/memory/src/processors/observational-memory/observational-memory.ts:1820
threadId: memoryContext.thread.id,
resourceId: memoryContext.resourceId,
};
}
// Fallback to MessageList's memoryInfo
const serialized = messageList.serialize();
if (serialized.memoryInfo?.threadId) {
return {
threadId: serialized.memoryInfo.threadId,
resourceId: serialized.memoryInfo.resourceId,
};
}
// In thread scope, threadId is required — without it OM would silently
// fall back to a resource-keyed record which causes deadlocks when
// multiple threads share the same resourceId.
if (this.scope === 'thread') {
throw new MastraError({
id: 'OBSERVATIONAL_MEMORY_THREAD_ID_REQUIRED',
domain: ErrorDomain.MASTRA_MEMORY,
category: ErrorCategory.USER,
details: { status: 400 },
text:
`ObservationalMemory (scope: 'thread') requires a threadId, but none was found in RequestContext or MessageList. ` +
`Ensure the agent is configured with Memory and a valid threadId is provided.`,
});
}
return null;
}
/**
* Save messages to storage, skipping messages that were already persisted by
* async buffering. Uses the message-level sealed flag (metadata.mastra.sealed)
* to detect already-persisted messages, avoiding redundant DB operations.
*View on GitHub (pinned to 75dd419e61)
Solutions
- Create/reuse a thread and pass its threadId (e.g. via RequestContext or by including thread-scoped messages in the MessageList).
- If per-thread state is not needed, switch ObservationalMemory to `scope: 'resource'`.
- Ensure the agent is configured with a working Memory instance so threadId resolution has a source.
- In API layers, require and forward the threadId on every request before invoking the agent.
Example fix
// before
await agent.generate('hello'); // no thread context
// after
await agent.generate('hello', {
memory: { thread: threadId, resource: resourceId },
}); Defensive patterns
Strategy: try-catch
Validate before calling
const threadId = requestContext.get?.('threadId') ?? messages.find(m => m.threadId)?.threadId;
if (memory?.observational?.scope === 'thread' && !threadId) {
throw new Error('scope: thread requires a threadId');
} Type guard
function hasThreadId(ctx: { threadId?: string }): ctx is { threadId: string } {
return typeof ctx.threadId === 'string' && ctx.threadId.length > 0;
} Try / catch
try {
await agent.generate(input, options);
} catch (e) {
if (e instanceof MastraError && e.id === 'OBSERVATIONAL_MEMORY_THREAD_ID_REQUIRED') {
// create a thread and retry with explicit memory context
const thread = await memory.createThread({ resourceId });
return agent.generate(input, { ...options, memory: { thread: thread.id, resource: resourceId } });
}
throw e;
} Prevention
- Always pass explicit memory context (thread + resource) on agent calls when using thread-scoped OM.
- Create the thread up front in request handlers before invoking the agent.
- Catch OBSERVATIONAL_MEMORY_THREAD_ID_REQUIRED in integration tests to catch callers that drop thread context.
- Switch to scope: 'resource' if per-thread identity is not actually required.
When it happens
Trigger: Calling `agent.generate`/`agent.stream` (or memory retrieval paths) against an agent whose memory uses ObservationalMemory with `scope: 'thread'`, while passing no threadId in RequestContext and no thread-scoped message in the MessageList (observational-memory.ts:1820).
Common situations: Fire-and-forget scripts or cron jobs that call the agent without creating/passing a thread; API routes that drop the threadId header; tests that construct RequestContext without thread metadata; migrating from resource-scoped OM to thread-scoped without updating callers.
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
- Factory rule version is required.
- MISSING_ARGUMENT
- No project specified. Pass --project <name|slug|id>, set MAS
- AGENT_SEND_STREAM_RESUME_MISSING_TARGET
- Received input message with wrong threadId. Input ${message.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/cce78c57212e810f.
Report an issue: GitHub.