Symptom: sending a message throws MissingToolResultsError (or the provider rejects the request) even though the previous turn looked fine.

Cause: a tool call part in the history has no matching tool result part. The usual story: a client-side tool was called, the UI never called addToolOutput, and the next request ships the dangling call.

Confirmation:
1. Log the messages array right before streamText. Walk the parts of the last assistant message.
2. Look for tool parts in a call/input state with no corresponding result. That dangling part is the failure.
3. Check the client: is there a code path where a tool call renders but the result handler is skipped (early return, unmounted component, missing await)?

Fix options:
- Complete the round: call addToolOutput({ tool: 'toolName', toolCallId, output }) for the pending call before sending.
- Or drop the dangling turn: filter the incomplete assistant message out of history before persisting or resending.
- Prevent recurrence: use sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls in useChat so rounds complete automatically.

Verification: resend and confirm the model responds normally. Then reload the page (persisted history path) and confirm the same conversation still sends.

Related errors on the approval path: InvalidToolApprovalError and InvalidToolApprovalSignatureError when approval metadata is malformed or fails verification.