vercel/ai · error · Error
${harnessId} ACP session ${sessionId} has no in-flight turn
Error message
${harnessId} ACP session ${sessionId} has no in-flight turn to suspend. What it means
Suspending captures the channel's last seen event id and detaches from the live bridge; it requires a turn to actually be in flight. If turnInFlight is false there is nothing to suspend, so doSuspendTurn throws. To end a session with no active turn, use detach instead.
Source
Thrown at packages/harness-acp/src/v1/acp-v1-harness.ts:1593
},
});
},
});
},
doCompact: async () => {
throw unsupported({
harnessId,
message: 'ACP v1 does not define manual session compaction.',
});
},
doSuspendTurn: async () => {
if (stopped) {
throw new Error(
`${harnessId} ACP session ${sessionId} is stopped; cannot suspend.`,
);
}
if (!turnInFlight) {
throw new Error(
`${harnessId} ACP session ${sessionId} has no in-flight turn to suspend.`,
);
}
stopped = true;
const lastSeenEventId = await channel.suspend();
return {
type: 'continue-turn',
harnessId,
specificationVersion: 'harness-v1',
data: createLifecycleData({
bridge: {
port: bridgePort,
token: bridgeToken,
lastSeenEventId,
...(sandboxId == null ? {} : { sandboxId }),
stateDir: bridgeStateDir,
},
}),View on GitHub (pinned to 69428b1f8b)
Solutions
- Call detach instead of suspendTurn when no turn is in flight.
- Suspend only while a turn is actively running (between prompt start and done), e.g. from the turn's event stream when an interruption is detected.
- Track turn state in your app and branch: suspend if in flight, detach otherwise.
- If the goal is just to preserve the session for later, detach with no in-flight turn returns a resume-session handle.
Example fix
// before
await session.suspendTurn(); // throws: no in-flight turn
// after
if (turnInFlight) {
await session.suspendTurn();
} else {
await session.detach();
} Defensive patterns
Strategy: validation
Validate before calling
if (turnInFlight) {
await session.suspendTurn();
} else {
await session.detach();
} Try / catch
try {
await session.suspendTurn();
} catch (e) {
if (e instanceof Error && e.message.includes('no in-flight turn to suspend')) {
await session.detach();
} else throw e;
} Prevention
- Only suspend while the turn's event stream is still active
- Branch on turn state: suspend when in flight, detach when idle
- Remember suspend ends the turn's liveness — do not suspend after done
When it happens
Trigger: Calling suspendTurn when no turn is active: before the first prompt, after the current turn finished (done), or after a prior suspend already ended the turn.
Common situations: Calling suspend during an idle period between turns assuming it pauses the session; suspending after the turn's done event already fired; a race where the turn completed before the suspend call executed.
Related errors
- ${harnessId} ACP session ${sessionId} is stopped; cannot sus
- ${harnessId} has no in-flight ACP turn to continue.
- ${harnessId} ACP session ${sessionId} is stopped; cannot det
- ${harnessId} ACP session ${sessionId} has an in-flight turn;
- claude-code session ${sessionId} is stopped; cannot suspend.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/f71b9d464b6bd30f.
Report an issue: GitHub.