shadcn-ui/ui · error
Only continuation turns materialize from a transcript.
Error message
Only continuation turns materialize from a transcript.
What it means
materializeDeferredTurn() rebuilds a deferred (continuation) turn's events from a live transcript; it requires turns[turnIndex].resolve to be set. Calling it on a regular, already-resolved turn is a logic error because that turn has no deferred resolution to run. This is an internal invariant guard, not a user-input error.
Source
Thrown at packages/helpers/src/core/chat.ts:496
: undefined,
...(call.approval
? {
approved: approved === true,
denied: approved === false,
}
: {}),
} as PendingToolCall<TOOLS>
}
function materializeDeferredTurn(
turnIndex: number,
messages: MESSAGE[]
): ResolvedTurn {
const turn = turns[turnIndex]
const resolve = turn.resolve
if (!resolve) {
throw new Error("Only continuation turns materialize from a transcript.")
}
const events = [...turn.events]
// The client merges a continuation into the prior assistant message as a
// new step. The step boundary keeps the resolved tool call out of the
// latest step so automatic sending does not retrigger on it.
events.push({ kind: "step-start" })
const pending = resolvePendingToolCalls(turnIndex, messages)
if (!pending.length) {
devWarn(
"A continuation turn resolved without a pending tool call. Its toolCall context is empty."
)
}
for (const call of pending) {View on GitHub (pinned to efac598707)
Solutions
- Guard callers so materializeDeferredTurn only runs when turns[turnIndex].resolve is defined.
- Re-check findNextAssistantTurnIndex logic if this fires from the built-in transport.
- Treat materializeDeferredTurn as internal API; do not call it from adapter or app code.
Example fix
// before
materializeDeferredTurn(turnIndex, messages)
// after
if (turns[turnIndex]?.resolve) {
materializeDeferredTurn(turnIndex, messages)
} Defensive patterns
Strategy: validation
Validate before calling
const turn = turns[turnIndex]
if (!turn?.resolve) {
// not a continuation turn; nothing to materialize
return
}
materializeDeferredTurn(turnIndex, messages) Type guard
const isDeferredTurn = (t: unknown): t is { resolve: (...a: unknown[]) => unknown } =>
Boolean(t && typeof (t as { resolve?: unknown }).resolve === "function") Prevention
- Treat materializeDeferredTurn as internal; do not call it from app or adapter code.
- Keep turn-index computation centralized so resolve aligns with the selected index.
When it happens
Trigger: Internal mis-indexing where findNextAssistantTurnIndex points at a non-deferred turn; calling materializeDeferredTurn directly with a wrong turnIndex; a transcript whose continuation marker was cleared.
Common situations: Bugs in turn-index resolution; custom adapters that invoke materializeDeferredTurn; corrupt transcript state from partial persistence.
Related errors
- get() cannot materialize a continuation turn without a live
- No assistant response found for this transcript.
- No assistant response found for this transcript.
- count must be a non-negative integer.
- A needsApproval tool call resolves from the user's decision;
AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12).
Data as JSON: /api/errors/ad1ed74d38de9d04.
Report an issue: GitHub.