{"record":{"id":"7381815abb7a2279","repo":"mastra-ai/mastra","slug":"resourceid-and-threadid-are-required-to-queue-a-me","errorCode":null,"errorMessage":"resourceId and threadId are required to queue a message","messagePattern":"resourceId and threadId are required to queue a message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/agent/thread-stream-runtime.ts","lineNumber":2670,"sourceCode":"      activeRecord = activeRunId ? state.threadRunsById.get(activeRunId) : undefined;\n      if (activeRecord && !this.#isThreadBlockingRun(state, activeRecord)) {\n        state.activeThreadRunIds.delete(key);\n        activeRecord = undefined;\n      }\n      runId ??= activeRunId;\n    }\n\n    if (runId) {\n      activeRecord ??= state.threadRunsById.get(runId);\n      if (activeRecord) {\n        key ??= this.#threadKey(activeRecord.resourceId, activeRecord.threadId);\n      }\n    }\n\n    const resourceId = target.resourceId ?? activeRecord?.resourceId;\n    const threadId = target.threadId ?? activeRecord?.threadId;\n    if (!resourceId || !threadId) {\n      throw new Error('resourceId and threadId are required to queue a message');\n    }\n\n    key ??= this.#threadKey(resourceId, threadId);\n    const signal = createMessageSignal(message, {\n      id: this.#generateSignalMessageId(agent, { resourceId, threadId }),\n      acceptedAt,\n    });\n    const queuedRunId = randomUUID();\n    const queuedStreamOptions = target.ifIdle?.streamOptions ?? activeRecord?.streamOptions;\n\n    if (activeRecord) {\n      const idleQueue = state.pendingIdleSignalsByThread.get(key) ?? [];\n      idleQueue.push({ agent, signal, runId: queuedRunId, resourceId, threadId, streamOptions: queuedStreamOptions });\n      state.pendingIdleSignalsByThread.set(key, idleQueue);\n      this.#watchThreadRunCompletion(state, pubsub, key, activeRecord);\n      return {\n        signal,\n        accepted: Promise.resolve({ action: 'deliver' as const, runId: queuedRunId }),","sourceCodeStart":2652,"sourceCodeEnd":2688,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/agent/thread-stream-runtime.ts#L2652-L2688","documentation":"AgentThreadStreamRuntime.queueMessage() throws this when it cannot resolve both a resourceId and a threadId for the signal target. Normally these come from the options object, but when omitted the runtime tries to infer them from an active run record (looked up by runId or thread key). If neither the options nor an active record yields both IDs, it cannot address a thread and throws.","triggerScenarios":"Calling runtime.queueMessage(agent, message, target) with (a) neither target.resourceId nor target.threadId set, and (b) no target.runId matching an active run record whose resourceId/threadId can be inferred.","commonSituations":"Building a custom pubsub/signal integration and passing only runId after the run already completed (record evicted from state); copying options objects and dropping resourceId/threadId; calling queueMessage from a context where only a message is available.","solutions":["Always pass both resourceId and threadId in the QueueAgentMessageOptions target object.","If you only have a runId, verify the run is still active (registered in the runtime state) before calling queueMessage, or capture resourceId/threadId when the run started.","Wrap the call in try/catch and fall back to agent.generate/stream directly when no thread context exists."],"exampleFix":"// before\nawait runtime.queueMessage(agent, message, {});\n// after\nawait runtime.queueMessage(agent, message, { resourceId: 'user-1', threadId: 'thread-1' });","handlingStrategy":"validation","validationCode":"function canQueueMessage(target) {\n  return Boolean(target.resourceId && target.threadId);\n}\nif (!canQueueMessage(target)) throw new Error('queueMessage needs resourceId and threadId');","typeGuard":"function hasThreadTarget(t: { resourceId?: string; threadId?: string }): t is { resourceId: string; threadId: string } {\n  return typeof t.resourceId === 'string' && t.resourceId.length > 0 && typeof t.threadId === 'string' && t.threadId.length > 0;\n}","tryCatchPattern":"try {\n  return runtime.queueMessage(agent, message, target);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('required to queue a message')) {\n    // no resolvable thread context — fall back to direct generation or rethrow with context\n  }\n  throw e;\n}","preventionTips":["Always construct signal targets from a helper that requires resourceId/threadId","Type the options narrowly instead of optional fields when a thread target is mandatory","Capture resourceId/threadId when starting a run and reuse them for signaling","Log the target object before calling to catch dropped fields in refactors"],"tags":["agent","memory","signal","missing-argument"],"backgroundTag":"missing-thread-context","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}