Skip to content

A tool response over the 64 MiB frame limit is dropped with only a log line — the agent's call never gets a reply #215

Description

@iceteaSA

When a tool result is too large to fit in a subc frame, the frame build fails and the error is logged. Nothing is sent back. The agent's tool call sits unanswered until some external timeout.

// crates/aft/src/subc/mod.rs:4438
Err(error) => {
    log::error!("subc attach: failed to build tool response frame: {error}");
}

That's the whole error arm — no fallback frame, no truncation, no error surfaced to the caller. Compare the arm directly above it, which at least logs a warning and is on a path where the frame was built successfully.

The limit it trips:

// subc-protocol frame.rs:47
if body.len() > MAX_FRAME_BODY_LEN as usize {
    return Err(FrameBuildError::BodyTooLarge ...)
}
// subc-protocol lib.rs:119
pub const MAX_FRAME_BODY_LEN: u32 = 64 * 1024 * 1024;

build_tool_response_frame (wire.rs:495) serializes the full ToolCallResult with no size guard of its own, so the protocol-level check is the only one.

The effective limit is about half of 64 MiB. For first-party (trusted) binds the envelope carries the rendered text twice — once as text, once inside structuredContent — which the code comments at wire.rs:418-419 acknowledge. So a single payload of ~32 MiB of real content is enough to trip it.

What reaches that size: a read of a large file, a broad grep/search with many hits, an outline over a large directory, or a big gather context pack. None of these are exotic — they're the tools most likely to produce a large result, and the failure mode is silent.

Severity: P2. It needs a large payload to trigger, but when it does the agent gets no error to act on — it just hangs, which is worse than a clear failure. An agent that receives "response too large" can retry with a narrower scope; an agent that receives nothing can't do anything.

Fix direction: on BodyTooLarge, send a small error frame back on the same correlation id — or truncate the text with an explicit marker and set a complete: false-style field, which would fit the honest-reporting convention in protocol.rs better than dropping. Either beats silence.


Provenance and limits. Found in a parallel read-only sweep; I verified the error arm at mod.rs:4434-4441 firsthand before filing. I have not reproduced the hang — no forced 64 MiB payload, no timing measurement. The claim is that the code path exists and has no reply on it, which is checkable by reading; whether it fires in practice depends on payload sizes I haven't sampled. Line numbers against 28930e09.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions