vercel/ai · error · RelayRequestError
No ACP prompt turn is active.
Error message
No ACP prompt turn is active.
What it means
Invoking a host tool through /invoke requires that an ACP prompt turn is currently bound to the relay (activeTurn set via bindTurn). If no turn is bound, the relay cannot emit tool calls or await tool results, so handleInvocation rejects with this 409 RelayRequestError before reading further body validation.
Source
Thrown at packages/harness-acp/src/v1/bridge/host-tool-relay.ts:272
async function handleInvocation({
body,
state,
serverName,
turn,
nextInvocationOrder,
}: {
body: unknown;
state: CatalogState;
serverName: string;
turn: HostToolRelayTurn | undefined;
nextInvocationOrder: () => number;
}): Promise<{
output: unknown;
isError?: boolean;
correlationToken: string;
}> {
if (turn == null) {
throw new RelayRequestError({
status: 409,
message: 'No ACP prompt turn is active.',
});
}
if (
!isRecord(body) ||
typeof body.requestId !== 'string' ||
typeof body.toolName !== 'string' ||
!isRecord(body.input) ||
!Number.isSafeInteger(body.catalogRevision)
) {
throw new RelayRequestError({
status: 400,
message: 'Invalid host tool relay request.',
});
}
if (body.catalogRevision !== state.revision) {
throw new RelayRequestError({View on GitHub (pinned to 69428b1f8b)
Solutions
- Only invoke host tools while an ACP prompt turn is active; re-issue the call from within the turn.
- Bind the turn before serving /invoke traffic: relay.bindTurn({ turn }) at turn start.
- Make the host-side client wait/retry until a turn becomes active, or return a clear error to the model to retry inside a prompt.
- Check that a prior turn's error path did not leave the relay unbound when you expected it bound.
Example fix
// before
await invokeTool(toolName, input); // fires any time
// after
if (!isTurnActive) {
throw new Error('Host tool invoked outside an ACP prompt turn; retry within a turn.');
}
await invokeTool(toolName, input); Defensive patterns
Strategy: try-catch
Validate before calling
// Caller-side check before invoking a host tool
function assertTurnActive(turn: HostToolRelayTurn | undefined) {
if (turn == null) {
throw new Error('Host tools can only be invoked during an active ACP prompt turn.');
}
} Try / catch
const res = await postJson(invokeUrl, body);
if (res.status === 409 && (await res.json()).error === 'No ACP prompt turn is active.') {
// defer the tool call until the next turn, or surface a retryable error to the agent
} Prevention
- Fire host tool calls only from within the prompt-turn lifecycle.
- Bind the turn before any MCP client can reach /invoke.
- Cancel or queue background work that outlives the turn instead of letting it invoke tools.
- In tests, always bind a turn before exercising /invoke.
When it happens
Trigger: POSTing /invoke between turns (after unbindTurn, before the next bindTurn), invoking during session startup before any prompt turn started, or after a turn ended/aborted and unbound while the MCP client still had a pending tool call.
Common situations: MCP client with a long-lived connection firing a tool call after the ACP turn finished; async background work in the agent deferring a tool invocation past turn end; a crashed turn never rebound; testing /invoke directly without a running prompt turn.
Related errors
- A host tool relay turn is already active.
- Unknown host tool relay endpoint.
- Invalid host tool relay credential.
- Invalid host tool catalog poll request.
- Invalid host tool catalog acknowledgment.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/95c21ac1746667b2.
Report an issue: GitHub.