zeroclaw-labs/zeroclaw · error · anyhow::Error

grok_cli max_acp_stdout_bytes must be between {} and {} byte

Error message

grok_cli max_acp_stdout_bytes must be between {} and {} bytes

What it means

max_acp_stdout_bytes caps the ACP stdout reader and must lie in [1_048_576, 67_108_864] bytes (1 MiB to 64 MiB); the default is 4 MiB. The minimum equals MAX_ACP_FRAME_BYTES so no single valid ACP frame is ever rejected by the cap.

Source

Thrown at crates/zeroclaw-providers/src/grok_cli.rs:507

            );
        }
        let path = Path::new(trimmed);
        if !path.is_absolute() {
            anyhow::bail!("grok_cli working_directory must be an absolute path");
        }
        let canonical = std::fs::canonicalize(path).map_err(|_| {
            anyhow::Error::msg("grok_cli working_directory does not exist or is inaccessible")
        })?;
        if !canonical.is_dir() {
            anyhow::bail!("grok_cli working_directory must identify a directory");
        }
        Ok(canonical)
    }

    fn validate_acp_stdout_limit(value: Option<usize>) -> anyhow::Result<usize> {
        let limit = value.unwrap_or(acp::DEFAULT_ACP_STDOUT_LIMIT_BYTES);
        if !(acp::MIN_ACP_STDOUT_LIMIT_BYTES..=acp::MAX_ACP_STDOUT_LIMIT_BYTES).contains(&limit) {
            anyhow::bail!(
                "grok_cli max_acp_stdout_bytes must be between {} and {} bytes",
                acp::MIN_ACP_STDOUT_LIMIT_BYTES,
                acp::MAX_ACP_STDOUT_LIMIT_BYTES
            );
        }
        Ok(limit)
    }

    fn normalize_and_validate_env_passthrough(names: Vec<String>) -> anyhow::Result<Vec<String>> {
        let mut normalized: Vec<String> = Vec::with_capacity(names.len());
        for name in names {
            let name = name.trim();
            if !is_valid_env_var_name(name) {
                anyhow::bail!(
                    "grok_cli env_passthrough entry `{name}` is invalid; expected [A-Za-z_][A-Za-z0-9_]*"
                );
            }
            if is_disallowed_provider_env_var(name) {

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Choose a value within 1_048_576..=67_108_864 bytes
  2. Omit the option to accept the 4 MiB default
  3. Raise toward 64 MiB only when frames are genuinely larger

Example fix

# before
max_acp_stdout_bytes = 65536

# after
max_acp_stdout_bytes = 8388608  # 8 MiB, within [1 MiB, 64 MiB]
Defensive patterns

Strategy: validation

Validate before calling

const ACP_MIN: usize = 1_048_576;
const ACP_MAX: usize = 67_108_864;
fn stdout_limit_ok(v: usize) -> bool { (ACP_MIN..=ACP_MAX).contains(&v) }

Type guard

fn stdout_limit_ok(v: usize) -> bool {
    (1_048_576..=67_108_864).contains(&v)
}

Prevention

When it happens

Trigger: Setting a sub-MiB limit (e.g. 65536 or 0) to 'save memory'; passing usize::MAX trying to disable the cap; confusing KiB and MiB units.

Common situations: Operators copying a bytes-looking number without unit math; attempts to disable limits on huge tool outputs; config generated from a different constant set.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/22c3a0a93cb095b7. Report an issue: GitHub.