n8n-io/n8n · error · Error
Thread ${ref.threadId}: the live turn is the first/only user
Error message
Thread ${ref.threadId}: the live turn is the first/only user turn — no prior turn to seed. Pin a later turn, or use a plain conversation case. What it means
Thrown when seeding a conversation case whose pinned live turn is the first (index 0) or only user turn — there are no prior turns to reconstruct as seed messages, so the seeded conversation would be empty. The harness needs at least one earlier user turn to build a meaningful pre-live context.
Source
Thrown at packages/@n8n/instance-ai/evaluations/harness/langsmith-seed.ts:388
// Split point: the live turn is sent live; everything strictly before it is the
// seed. Default = the last user turn; a `liveTurnRunId` pin (LangTracer's live-turn
// picker) moves it earlier, discarding the real turns at/after it.
const userTurns = rootRuns.filter((r) => userMessageOf(r) !== undefined);
let liveIndex = userTurns.length - 1; // default: last user turn (unchanged behavior)
if (ref.liveTurnRunId) {
const idx = userTurns.findIndex((r) => r.id === ref.liveTurnRunId);
if (idx === -1) {
console.warn(
`[seed] Thread ${ref.threadId}: pinned liveTurnRunId ${ref.liveTurnRunId} not found among ` +
`${userTurns.length} user turn(s) — falling back to the last user turn. (LangTracer pins the ` +
"agent_role=message_turn root id; verify it matches the name==='turn' root id.)",
);
} else {
liveIndex = idx;
}
}
if (liveIndex < 1) {
throw new Error(
`Thread ${ref.threadId}: the live turn is the first/only user turn — no prior turn to seed. ` +
'Pin a later turn, or use a plain conversation case.',
);
}
const liveTurnRun = userTurns[liveIndex];
const boundaryMs = new Date(liveTurnRun.start_time ?? NaN).getTime();
const liveTurn = userMessageOf(liveTurnRun)!;
const messages = buildSeedMessages(rootRuns, toolRuns, boundaryMs);
if (messages.length === 0) {
throw new Error(
`Thread ${ref.threadId} reconstructed to zero seed messages before the live turn — the trace shape may have drifted (expected root runs named 'turn' with inputs.message / outputs.response).`,
);
}
const sdkVersion = rootRuns
.map((r) => asString(metadata(r).workflow_sdk_version))
.find((v) => v !== undefined);
const workflows = buildSeedWorkflows(workflowScanRuns, boundaryMs, ref.threadId, sdkVersion);View on GitHub (pinned to 5ac6606e81)
Solutions
- Pin liveTurnRunId to a later user turn (index >= 1) so prior turns exist to seed.
- If the case is intentionally single-turn, switch it to a plain conversation case (no seed reference) instead of a seeded one.
- Verify the liveTurnRunId matches the LangTracer-pinned agent_role=message_turn root id, since a wrong pin falls back to the last turn which may also be the first.
- Re-record the underlying thread to capture additional turns before the live one.
Example fix
// before — case.json pins the only user turn
{ "seed": { "kind": "langsmith", "threadId": "t1", "liveTurnRunId": "<first-turn-id>" } }
// after — pin a later turn, or drop the seed for a plain case
{ "seed": { "kind": "langsmith", "threadId": "t1", "liveTurnRunId": "<second-turn-id>" } }
// or remove the `seed` block entirely for a plain conversation case Defensive patterns
Strategy: validation
Validate before calling
function canSeedLiveTurn(userTurns: { id: string }[], liveTurnRunId?: string): boolean {
const idx = liveTurnRunId
? userTurns.findIndex((r) => r.id === liveTurnRunId)
: userTurns.length - 1;
return idx > 0; // need at least one prior turn
}
if (!canSeedLiveTurn(userTurns, ref.liveTurnRunId)) {
throw new Error('cannot seed: live turn is the first/only turn; use a plain case instead');
} Type guard
null
Try / catch
try {
buildSeedFromLangsmith(client, ref, sourceProject, logger);
} catch (e) {
if (e instanceof Error && /no prior turn to seed/.test(e.message)) {
// downgrade this case to a plain conversation case, or pick a later turn
return asPlainCase(ref);
}
throw e;
} Prevention
- When authoring a case, assert the pinned liveTurnRunId is not the first user turn.
- Use LangTracer's pinned root id and double-check it resolves to index >= 1.
- For single-turn scenarios, prefer plain conversation cases over seeded ones.
When it happens
Trigger: A conversation case with exactly one user turn where liveTurnRunId points at that turn; liveTurnRunId pinned to the very first of several turns (liveIndex === 0); a case that should have been authored as a plain (non-seeded) conversation case but was misclassified.
Common situations: Authoring a seeded eval case from a thread where the interesting behaviour is in turn 1 itself; LangTracer pinning a root id that resolves to index 0; converting a single-shot Q&A into a seeded case by mistake.
Related errors
- No runs for thread ${ref.threadId} in LangSmith project "${s
- A case declares ${String(byName.size)} distinct scenario see
- Node type ${nodeType} not found
- Could not read node catalogue at ${jsonPath}: ${message} Run
- Model ID is required
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/edb081485919b5cf.
Report an issue: GitHub.