astrid-runtime/astrid · error

MCP attach registration is missing or too large

Error message

MCP attach registration is missing or too large

What it means

read_gateway_request_inner reads the registration preface byte-by-byte up to MAX_REGISTRATION_BYTES (16 KiB) awaiting a newline. If the stream ends or the size ceiling is hit before a terminating newline arrives, the gateway bails with 'missing or too large' — covering both truncated prefaces and oversized/DoS-y registrations.

Source

Thrown at crates/astrid-cli/src/commands/mcp/gateway.rs:898

async fn read_gateway_request_inner<R>(reader: &mut BufReader<R>) -> Result<GatewayRequest>
where
    R: AsyncRead + Unpin,
{
    let mut line = Vec::new();
    let mut terminated = false;
    for _ in 0..=MAX_REGISTRATION_BYTES {
        let byte = reader
            .read_u8()
            .await
            .context("failed to read MCP attach registration")?;
        if byte == b'\n' {
            terminated = true;
            break;
        }
        line.push(byte);
    }
    if !terminated {
        anyhow::bail!("MCP attach registration is missing or too large");
    }
    let request: GatewayRequest =
        serde_json::from_slice(&line).context("MCP gateway registration is not valid JSON")?;
    match &request {
        GatewayRequest::Control(control) => {
            if control.version != GATEWAY_CONTROL_VERSION {
                anyhow::bail!(
                    "unsupported MCP gateway control version {}",
                    control.version
                );
            }
            if control.pid == 0 || control.hook_token.trim().is_empty() {
                anyhow::bail!("MCP gateway control authority is incomplete");
            }
        },
        GatewayRequest::Attach(registration) => validate_registration(registration)?,
    }
    Ok(request)

View on GitHub (pinned to affd8760f4)

Solutions

  1. Terminate the registration JSON with a single newline ('\n') after the last byte.
  2. Keep the entire registration preface under 16 KiB; move large data (tokens, env) out of the registration.
  3. Write the preface promptly after connect — the gateway enforces REGISTRATION_TIMEOUT (5s) and half-open sockets are dropped.
  4. If you legitimately need more preface data, that ceiling (MAX_REGISTRATION_BYTES) is a protocol constant and requires a code change on both ends.

Example fix

// before
stream.write_all(json_bytes).await?;
// after
let mut preface = json_bytes.to_vec();
preface.push(b'\n');
stream.write_all(&preface).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn preface_ok(json: &str) -> bool {
    json.len() <= 16 * 1024 && !json.contains('\n')
}

Try / catch

match result {
    Err(e) if e.to_string().contains("missing or too large") => eprintln!("registration preface must be a newline-terminated line < 16 KiB"),
    other => other?,
}

Prevention

When it happens

Trigger: An attach client sends a registration line longer than 16 KiB, sends bytes without ever writing '\n' before EOF, or stalls so REGISTRATION_TIMEOUT expires leaving a non-terminated buffer.

Common situations: A hand-rolled client forgets the trailing newline after the JSON preface; a client embeds huge credentials/blobs into the registration; a broken/half-open socket delivers a partial line; a malicious or buggy scanner hits the listener.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


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