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

  1. Only invoke host tools while an ACP prompt turn is active; re-issue the call from within the turn.
  2. Bind the turn before serving /invoke traffic: relay.bindTurn({ turn }) at turn start.
  3. 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.
  4. 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

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


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/95c21ac1746667b2. Report an issue: GitHub.