mastra-ai/mastra · error

tool_result must be preceded by a tool_call with the same to

Error message

tool_result must be preceded by a tool_call with the same toolCallId

What it means

This error is thrown when processing a stream part carrying a tool result whose toolCallId does not match any pending tool invocation in the message being built. The library maintains an ordered list of toolInvocations; a 'tool-result' must correspond to a 'tool-call' that was previously emitted with the same toolCallId, otherwise the message state machine is inconsistent.

Source

Thrown at client-sdks/client-js/src/resources/agent.ts:1585

            updateToolInvocationPart(value.toolCallId, invocation, (value as MaybeProviderMetadata).providerMetadata);

            execUpdate();
          }
        }
      },
      onToolResultPart(value) {
        const toolInvocations = message.toolInvocations;

        if (toolInvocations == null) {
          throw new Error('tool_result must be preceded by a tool_call');
        }

        // find if there is any tool invocation with the same toolCallId
        // and replace it with the result
        const toolInvocationIndex = toolInvocations.findIndex(invocation => invocation.toolCallId === value.toolCallId);

        if (toolInvocationIndex === -1) {
          throw new Error('tool_result must be preceded by a tool_call with the same toolCallId');
        }

        const invocation = {
          ...toolInvocations[toolInvocationIndex],
          state: 'result' as const,
          ...value,
        } as const;

        toolInvocations[toolInvocationIndex] = invocation as ToolInvocation;

        updateToolInvocationPart(
          value.toolCallId,
          invocation as ToolInvocation,
          (value as MaybeProviderMetadata).providerMetadata,
        );

        execUpdate();
      },

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure the full stream is consumed from the start — do not skip or drop tool-call chunks before the matching tool-result.
  2. Check any stream middleware/processors for logic that removes or reorders tool-call parts.
  3. Clear stale conversation memory so the client rebuilds messages from a consistent stream.
  4. Verify server and client-js versions match and use the same UI-message stream protocol.

Example fix

// before: filtering stream parts
stream.processDataStream({ onChunk: c => { if (c.type !== 'tool-call') handle(c); } });
// after: handle every part so toolInvocations is populated first
stream.processDataStream({ onChunk: c => handle(c) });
Defensive patterns

Strategy: validation

Validate before calling

function canApplyToolResult(message, toolCallId) {
  return Array.isArray(message.toolInvocations) &&
    message.toolInvocations.some(inv => inv.toolCallId === toolCallId);
}
// before merging a tool-result part: if (!canApplyToolResult(message, value.toolCallId)) skip or buffer it;

Type guard

function hasMatchingToolInvocation(message: UIMessage, toolCallId: string): boolean {
  return Array.isArray(message.toolInvocations) &&
    message.toolInvocations.some(i => i.toolCallId === toolCallId);
}

Try / catch

try {
  await stream.processDataStream({ onChunk, onFinish });
} catch (err) {
  if (err instanceof Error && err.message.includes('tool_result must be preceded')) {
    console.error('Inconsistent tool stream: result without matching call', err.message);
  } else throw err;
}

Prevention

When it happens

Trigger: Consuming a stream (agent.stream/.streamVNext UI message stream) where a tool-result part arrives while message.toolInvocations is missing an entry with a matching toolCallId — e.g. a result part for a call the client never saw, a duplicated/replayed result, or a stream where earlier tool-call chunks were dropped or filtered.

Common situations: Custom middleware or processors that strip tool-call parts; resuming/remembering a conversation where stored messages lost their tool-call entries; feeding a server stream through a transform that reorders or drops chunks; version mismatches between server and @mastra/client-js stream formats.

Related errors


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