windmill-labs/windmill · error
No actual user message found to restart from
Error message
No actual user message found to restart from
What it means
During restart-from-message, the transcript index is mapped to the underlying API message index. A display message may be a placeholder (index -1) or out of range, meaning its API counterpart was removed by drop-oldest compaction — restarting from it would restart from an empty history — so this error is thrown.
Source
Thrown at frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts:4039
images ?? [],
files ?? []
)
}
// "Text", not "message": chip edits are the part that does not survive.
sendUserToast('This session is running in another tab. Your text was kept.', true)
return
}
// Resolve the API restart point BEFORE reserving bytes or truncating: a
// stale index must fail while nothing has been mutated, or the transcript
// would be left truncated with the reservation leaked. A negative index
// marks a message whose API counterpart was removed by drop-oldest
// compaction — everything before it went too, so restarting from it
// restarts from an empty history.
const actualMessageIndex =
userMessage.index < 0 ? 0 : userMessage.index < this.messages.length ? userMessage.index : -1
if (actualMessageIndex === -1) {
throw new Error('No actual user message found to restart from')
}
// Read while both arrays are intact: storedImages pairs the API message with
// its transcript entry, and the truncations below drop them.
const sentImages = this.storedImages(displayMessageIndex)
// Reserve the resent files' bytes across the gap between the edit box
// unmounting and the optimistic message landing. A per-resend token owns the
// reservation (sendRequest releases only this key) so an unrelated or
// concurrent send never clears it. Set before the slice below removes the
// message from the transcript, so those bytes are always accounted.
const resendReservationKey = `resend:${createLongHash()}`
const resentFiles = files ?? userMessage.files ?? []
this.setComposerStaged(
resendReservationKey,
null,
resentFiles.reduce((sum, f) => sum + textByteLength(f.content), 0)
)View on GitHub (pinned to e474e8803c)
Solutions
- Restart from a more recent message whose API entry still exists.
- Refresh the session/transcript from the server to get post-compaction state before restarting.
- Start a new session instead of restarting from a compacted message.
- Disable/raise the drop-oldest compaction threshold if restarts from old messages are required.
Example fix
// before
await manager.restartFrom(oldDisplayIndex) // may hit compacted message
// after
const msg = manager.displayMessages[oldDisplayIndex]
if (msg && msg.index >= 0 && msg.index < manager.messages.length) {
await manager.restartFrom(oldDisplayIndex)
} else {
toast('This message can no longer be restarted from — start a new session')
} Defensive patterns
Strategy: validation
Validate before calling
const msg = manager.displayMessages[i]
if (!msg || msg.index < 0 || msg.index >= manager.messages.length) {
throw new Error('Message no longer restartable (compacted)')
} Try / catch
try {
await manager.restartFrom(i)
} catch (e) {
if (e.message.includes('restart from')) {
toast('This message was compacted; start a new session instead')
return
}
throw e
} Prevention
- Restart only from recent messages in long, compacted sessions.
- Refresh the transcript from the server before restart attempts.
- Compensate for drop-oldest compaction by disabling restart UI on placeholder messages (index -1).
When it happens
Trigger: Calling the restart method on a user message whose stored index is -1 (compaction placeholder) or >= messages.length — i.e. the conversation was compacted or truncated after the user captured the message reference.
Common situations: Long conversations where drop-oldest compaction removed the oldest API messages while the UI still shows them; attempting to restart from a very old message in a big session; stale UI state after background compaction.
Related errors
- AI response was empty
- AI response contained empty code block
- AI response did not contain valid code. Please try rephrasin
- An unexpected error occurred. Please try again.
- No flow helpers found
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/8898c57506edf9f3.
Report an issue: GitHub.