mastra-ai/mastra · error · Error

[Processor:${processor.id}] computeStateSignal could not loa

Error message

[Processor:${processor.id}] computeStateSignal could not load thread ${resolvedThreadId}

What it means

After memory is resolved, runComputeStateSignal loads the thread via memory.getThreadById({ threadId }) (falling back to the thread embedded in the request context). If neither exists, the thread-scoped state signal cannot proceed and the runner throws naming the processor and missing threadId.

Source

Thrown at packages/core/src/processors/runner.ts:405

    if (!resolvedMemory) {
      throw new Error(
        `[Processor:${processor.id}] computeStateSignal requires Mastra memory with an active resourceId and threadId`,
      );
    }

    // Memory is configured but this invocation has no thread/resource identity
    // (e.g. an ephemeral workflow agent step). State signals are thread-scoped,
    // so skip rather than throw.
    if (!resolvedThreadId || !resolvedResourceId) {
      this.logger.debug(
        `[Processor:${processor.id}] computeStateSignal skipped — no threadId/resourceId resolved for this invocation`,
      );
      return;
    }

    const loadedThread = (await resolvedMemory.getThreadById({ threadId: resolvedThreadId })) ?? memoryContext?.thread;
    if (!loadedThread) {
      throw new Error(`[Processor:${processor.id}] computeStateSignal could not load thread ${resolvedThreadId}`);
    }
    let thread = {
      ...loadedThread,
      id: resolvedThreadId,
      resourceId: loadedThread.resourceId ?? resolvedResourceId,
      createdAt: loadedThread.createdAt ?? new Date(),
      updatedAt: loadedThread.updatedAt ?? new Date(),
      metadata: loadedThread.metadata,
    };

    const stateId = processor.stateId ?? processor.id;
    const beforeAddStateSignal = rotateResponseMessageId;
    const trackingById = getStateSignalsMetadata(thread.metadata);
    const tracking = trackingById[stateId];
    const { activeStateSignals, contextWindow, lastSnapshot, deltasSinceSnapshot } = await resolveStateSignalHistory({
      messageList,
      memory: resolvedMemory,
      threadId: resolvedThreadId,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Create the thread first via memory.createThread({ threadId, resourceId }) before running processors that emit state signals.
  2. Verify the thread exists: await memory.getThreadById({ threadId }) — if null, use a valid thread ID.
  3. Check that the memory storage backend is the one where the thread was created (same DB/connection).
  4. Pass the loaded thread object in the request context so the memoryContext?.thread fallback applies.

Example fix

// before
await run(input, { memory: { thread: 'ghost-thread', resource: 'u1' } }); // never created
// after
await memory.createThread({ threadId: 'ghost-thread', resourceId: 'u1' });
await run(input, { memory: { thread: 'ghost-thread', resource: 'u1' } });
Defensive patterns

Strategy: validation

Validate before calling

const thread = await memory.getThreadById({ threadId });
if (!thread) {
  await memory.createThread({ threadId, resourceId });
}

Try / catch

try {
  await run(input, { memory: { thread: threadId, resource: resourceId } });
} catch (e) {
  if (e?.message?.includes('could not load thread')) {
    await memory.createThread({ threadId, resourceId });
    // retry once
  } else throw e;
}

Prevention

When it happens

Trigger: runComputeStateSignal is called with a resolvedThreadId that does not exist in the memory store: stale/expired thread ID, wrong storage backend, thread deleted between calls, or a threadId string that was never created via memory.createThread.

Common situations: Pointing at a thread ID from a different environment (dev vs prod storage); switching storage adapters without migrating threads; typos/hardcoded thread IDs; storage cleared (in-memory storage restarted).

Related errors


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