astrid-runtime/astrid · error

MCP gateway rejected {operation:?}: {}

Error message

MCP gateway rejected {operation:?}: {}

What it means

The gateway accepted the control request but responded with ack.ok = false; the error carries the operation name and the gateway's error string (or 'unknown gateway failure'). This is the gateway-side failure surfacing through the control protocol.

Source

Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:682

        .await
        .context("failed to terminate MCP gateway control")?;
    write_half
        .flush()
        .await
        .context("failed to flush MCP gateway control")?;

    let mut reader = BufReader::new(read_half);
    let response = tokio::time::timeout(READY_TIMEOUT, read_bounded_line(&mut reader))
        .await
        .context("timed out waiting for MCP gateway control acknowledgement")??;
    let ack: GatewayControlAck =
        serde_json::from_slice(&response).context("invalid MCP gateway control acknowledgement")?;
    if ack.version != GATEWAY_CONTROL_VERSION || ack.operation != operation || ack.pid != record.pid
    {
        anyhow::bail!("MCP gateway returned an unbound control acknowledgement");
    }
    if !ack.ok {
        anyhow::bail!(
            "MCP gateway rejected {operation:?}: {}",
            ack.error.as_deref().unwrap_or("unknown gateway failure")
        );
    }
    Ok(ack)
}

pub(crate) async fn read_bounded_line<R>(reader: &mut R) -> Result<Vec<u8>>
where
    R: tokio::io::AsyncRead + Unpin,
{
    let mut line = Vec::new();
    for _ in 0..=MAX_CONTROL_BYTES {
        let byte = reader
            .read_u8()
            .await
            .context("failed to read control frame")?;
        if byte == b'\n' {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Read the gateway's error text in the message to identify the gateway-side cause
  2. Retry the operation once the gateway is idle, or restart the gateway entirely
  3. Check gateway logs for the corresponding failure around the same timestamp
  4. Verify CLI/gateway version compatibility if the operation is reported unknown

Example fix

// before
let ack = request_gateway_control(...).await?;
// after: handle gateway-side rejection
match request_gateway_control(...).await {
    Err(e) if e.to_string().contains("MCP gateway rejected") => {
        eprintln!("gateway refused: {e}; retrying after restart");
        restart_gateway().await?;
    },
    other => other?,
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure gateway is healthy before issuing control ops
let health = ping_gateway(&gateway_socket_path()?).await;
anyhow::ensure!(health.is_ok(), "gateway unhealthy; restart before control ops");

Try / catch

match request_gateway_control(...).await {
    Err(e) if e.to_string().contains("MCP gateway rejected") => {
        eprintln!("gateway refused operation: {e}");
        // parse gateway error text and decide: retry vs restart
    },
    other => other?,
}

Prevention

When it happens

Trigger: Any control operation (e.g. shutdown/restart requested via request_gateway_control by wait_for_gateway or stop_ready_gateway) where the gateway sets ok=false in its GatewayControlAck.

Common situations: Gateway busy or shutting down while asked to stop; internal gateway error performing the operation; mismatched gateway build that doesn't implement the requested operation and reports failure.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/9be5f78fb0474e61. Report an issue: GitHub.