can1357/oh-my-pi · error · AIError.ValidationError
Cursor ${targetModelId} cannot continue history from a diffe
Error message
Cursor ${targetModelId} cannot continue history from a different model (${msg.provider}/${msg.model}); start a new session. What it means
Cursor K3 models reconstruct prior assistant turns' signed reasoning from the conversation history. If any prior assistant message was produced by a different model (different provider/model id), there is no K3-signed thinking to replay, so the library throws ValidationError telling you to start a new session instead of silently corrupting context.
Source
Thrown at packages/ai/src/providers/cursor.ts:4785
function assertCursorKimiK3HistoryReplayable(
messages: Message[],
activeUserMessageIndex: number,
targetModelId: string | undefined,
): void {
if (!targetModelId || classifyModel("cursor", targetModelId).family !== "k3") return;
const historyEnd = activeUserMessageIndex >= 0 ? activeUserMessageIndex : messages.length;
const missingThinkingTurns: number[] = [];
const newlyWarnedKeys: string[] = [];
let assistantTurn = 0;
for (let i = 0; i < historyEnd; i++) {
const msg = messages[i];
if (msg.role !== "assistant") continue;
assistantTurn++;
const isSameCursorModel = msg.api === "cursor-agent" && msg.provider === "cursor" && msg.model === targetModelId;
if (!isSameCursorModel) {
// Foreign history genuinely cannot replay K3 thinking: another model's
// turns carry no K3-signed reasoning to reconstruct.
throw new AIError.ValidationError(
`Cursor ${targetModelId} cannot continue history from a different model (${msg.provider}/${msg.model}); start a new session.`,
);
}
const hasThinking = msg.content.some(item => item.type === "thinking" && item.thinking.length > 0);
if (hasThinking) continue;
const warningKey = `${msg.api}\0${msg.provider}\0${msg.model}\0${msg.timestamp}`;
if (warnedCursorKimiK3ReplayMessages.has(warningKey)) continue;
missingThinkingTurns.push(assistantTurn);
newlyWarnedKeys.push(warningKey);
}
if (missingThinkingTurns.length === 0) return;
for (const key of newlyWarnedKeys) warnedCursorKimiK3ReplayMessages.add(key);
logger.warn(
`Cursor kimi-k3 history contains same-model assistant turn(s) ${missingThinkingTurns.join(", ")} without thinking blocks; replaying those spans without reasoning may make generation less stable`,
{ model: targetModelId, assistantTurns: missingThinkingTurns },
);
}
View on GitHub (pinned to 9690622007)
Solutions
- Start a new session/conversation when switching to a different Cursor K3 model, as the message says.
- Filter or truncate history to only assistant turns from the exact same cursor model before calling.
- Route the request back to the original model that produced the history if continuation is required.
- Adjust session bookkeeping so model changes reset the stored transcript instead of replaying foreign turns.
Example fix
// before
await streamCursor(newModel, { ...context, messages: oldMessages });
// after
const sameModelMessages = oldMessages.filter(
m => m.role !== "assistant" || (m.provider === "cursor" && m.model === newModel.id),
);
await streamCursor(newModel, { ...context, messages: sameModelMessages }); Defensive patterns
Strategy: validation
Validate before calling
const foreign = messages.find(m => m.role === "assistant" &&
!(m.api === "cursor-agent" && m.provider === "cursor" && m.model === targetModelId));
if (foreign) {
// start a new session or filter history before calling Cursor
} Type guard
null
Try / catch
try {
await streamCursor(model, ctx, { messages, ...options });
} catch (err) {
if (err instanceof AIError.ValidationError && err.message.includes("cannot continue history from a different model")) {
// reset the session: clear transcript or spin up a new conversation
} else throw err;
} Prevention
- Reset conversation transcripts whenever the user switches Cursor models.
- Tag assistant messages with provider/model and filter before replay.
- Never mix fallback-provider assistant turns into Cursor K3 history.
When it happens
Trigger: Calling the Cursor streaming path with a conversation history that includes assistant messages where msg.api !== "cursor-agent" or msg.provider !== "cursor" or msg.model !== targetModelId — typically switching models mid-session (e.g. from claude to a cursor K3 model).
Common situations: User switches models in the middle of a chat and the client replays full history; a fallback route substituted another provider's assistant turns into the transcript; session persistence across a model upgrade changes the model id string.
Related errors
- Cursor blob not found
- Invalid RPC message cursor
- Unsupported language '{value}'. Supported: {}
- Unable to infer language from file extension: {}. Specify `l
- Invalid pattern: {err}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3d2d900c2f929e31.
Report an issue: GitHub.