mastra-ai/mastra · error
resourceId and threadId are required to send a state signal
Error message
resourceId and threadId are required to send a state signal
What it means
AgentThreadStreamRuntime.sendStateSignal() throws this when target.resourceId or target.threadId is missing. Unlike queueMessage, sendStateSignal performs no inference from active run records — the caller must supply both IDs up front so the state signal can be persisted to the correct memory thread.
Source
Thrown at packages/core/src/agent/thread-stream-runtime.ts:2707
};
}
return this.sendSignal<OUTPUT>(
agent,
signal,
{ ...target, runId, resourceId, threadId, ifIdle: { ...target.ifIdle, behavior: 'wake' } },
pubsub,
);
}
async sendStateSignal<OUTPUT = unknown>(
agent: Agent<any, any, any, any>,
stateInput: AgentStateSignalInput,
target: SendAgentStateSignalOptions<OUTPUT>,
pubsub?: PubSub,
): Promise<SendAgentStateSignalResult<OUTPUT>> {
if (!target.resourceId || !target.threadId) {
throw new Error('resourceId and threadId are required to send a state signal');
}
const resourceId = target.resourceId;
const threadId = target.threadId;
const requestContext = target.ifIdle?.streamOptions?.requestContext;
const memoryContext = parseMemoryRequestContext(requestContext);
const memory = await agent.getMemory({ requestContext });
if (!memory) {
throw new Error('sendStateSignal requires Mastra memory');
}
const loadedThread = (await memory.getThreadById({ threadId })) ?? memoryContext?.thread;
if (!loadedThread) {
throw new Error(`sendStateSignal could not load thread ${threadId}`);
}
const thread = {
...loadedThread,View on GitHub (pinned to 75dd419e61)
Solutions
- Pass both resourceId and threadId in the target options before calling sendStateSignal.
- Add a pre-call guard that asserts both IDs are non-empty strings.
- If the IDs come from a request/session object, validate them at the API boundary instead of at signal time.
Example fix
// before
await runtime.sendStateSignal(agent, state, {});
// after
await runtime.sendStateSignal(agent, state, { resourceId: 'user-1', threadId: 'thread-1' }); Defensive patterns
Strategy: validation
Validate before calling
if (!target?.resourceId || !target?.threadId) {
throw new Error('sendStateSignal requires resourceId and threadId');
} Type guard
function isStateSignalTarget<T>(t: SendAgentStateSignalOptions<T>): t is SendAgentStateSignalOptions<T> & { resourceId: string; threadId: string } {
return Boolean(t.resourceId && t.threadId);
} Try / catch
try {
return await runtime.sendStateSignal(agent, state, target);
} catch (e) {
if (e instanceof Error && e.message.includes('required to send a state signal')) {
// surface a 400-style validation error to the caller
}
throw e;
} Prevention
- Validate signal options at the API/route boundary before reaching the runtime
- Keep resourceId/threadId in one typed object threaded through your code
- Add unit tests asserting the error for missing IDs
When it happens
Trigger: Calling runtime.sendStateSignal(agent, stateInput, target) with resourceId or threadId undefined/null in the SendAgentStateSignalOptions target.
Common situations: Partially constructed options objects when routing signals dynamically; type-looseness letting { resourceId } without threadId compile; migrating code that previously targeted an active run by runId only.
Related errors
- resourceId and threadId are required to queue a message
- resourceId and threadId are required to persist an active si
- sendStateSignal requires Mastra memory
- No active agent run found for signal target
- Could not generate title from input ${JSON.stringify(message
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/ea5ba59471bba159.
Report an issue: GitHub.