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
- Read the gateway's error text in the message to identify the gateway-side cause
- Retry the operation once the gateway is idle, or restart the gateway entirely
- Check gateway logs for the corresponding failure around the same timestamp
- 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
- Read the gateway's embedded error string before retrying
- Monitor gateway logs alongside CLI operations
- Keep gateway and CLI versions compatible
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
- daemon request: {e}
- unexpected response shape: {other:?}
- registry reply not JSON: {e}
- registry did not respond
- registry reply was not an IPC message
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/9be5f78fb0474e61.
Report an issue: GitHub.