astrid-runtime/astrid · error

models response too large

Error message

models response too large (advertised {} bytes; limit {MAX_RESPONSE_BYTES})

What it means

To guard against hostile operator-supplied endpoints, fetch_options rejects up-front any response whose advertised Content-Length exceeds MAX_RESPONSE_BYTES, before reading the body. This bounds memory use from untrusted servers.

Solutions

  1. Point the endpoint at a real models-listing API that returns small JSON responses
  2. If the server genuinely returns more than the cap, reduce response size or proxy it through a filtering service
  3. Serve the list from a trimmed endpoint
Defensive patterns

Strategy: try-catch

Validate before calling

if let Some(len) = head.content_length() {
    if len > MAX_RESPONSE_BYTES {
        eprintln!("response too large; skipping discovery");
        return Ok(());
    }
}

Try / catch

match fetch_options(opts, values).await {
    Err(e) if e.to_string().contains("too large") => prompt_free_text()?,
    other => other?,
}

Prevention

When it happens

Trigger: The models endpoint responds with a Content-Length header larger than MAX_RESPONSE_BYTES — e.g. pointing at a huge file, a misconfigured proxy, or a malicious server.

Common situations: Pointing discovery at a generic file host or wrong service that returns large payloads; server misbehaving with giant advertised bodies.

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/61dbc55adfe77c0e. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-cli/src/commands/capsule/model_discovery.rs:245

    let mut request = client.get(&url);
    if let Some(token) = bearer {
        request = request.bearer_auth(token);
    }

    let response = request.send().await?;
    anyhow::ensure!(
        response.status().is_success(),
        "models endpoint returned HTTP {}",
        response.status()
    );

    // Cap the body: the endpoint is operator-supplied and otherwise
    // unbounded. Reject up-front on an advertised over-limit length so a
    // hostile `Content-Length` can't even start a large transfer (fast
    // path), then stream-read with the same bound so an absent/lying length
    // (e.g. a chunked response with no `Content-Length`) cannot OOM the
    // installer either. An over-limit response errors → free-text fallback.
    anyhow::ensure!(
        response
            .content_length()
            .is_none_or(|len| len <= MAX_RESPONSE_BYTES as u64),
        "models response too large (advertised {} bytes; limit {MAX_RESPONSE_BYTES})",
        response.content_length().unwrap_or_default()
    );
    let body = read_capped_body(response).await?;
    let options = parse_options_response(&body, opts.select_or_default());
    anyhow::ensure!(
        !options.is_empty(),
        "models endpoint returned no usable options"
    );
    Ok(options)
}

/// Stream the response body into memory under a hard [`MAX_RESPONSE_BYTES`]
/// cap, then decode it as UTF-8.
///

View on GitHub (pinned to affd8760f4)