quickwit-oss/quickwit · error

max gRPC message size (`grpc.max_message_size`) must be at…

Error message

max gRPC message size (`grpc.max_message_size`) must be at least 1MB, got `{}`

What it means

GrpcConfig::validate enforces a floor of 1MB on `max_message_size`, since gRPC messages smaller than that would break inter-service communication (Quickwit's internal defaults are 20MB). Values below the floor are rejected with the configured size shown in the message.

Solutions

  1. Set `grpc.max_message_size` to at least `1MB` — the default `20MB` is recommended.
  2. Use correct ByteSize units: `20MB`, `50MB`, etc.; confirm no unit typo dropped the value below the floor.
  3. Do not set it to 0 or omit-with-zero: rely on the default by removing the key entirely if you want stock behavior.

Example fix

# before
grpc:
  max_message_size: 512KB
# after
grpc:
  max_message_size: 20MB
Defensive patterns

Strategy: validation

Validate before calling

const min = 1024 * 1024; // 1MB
const toBytes = (s) => { /* parse '20MB' style strings */ };
if (toBytes(cfg.grpc?.max_message_size ?? '20MB') < min) {
  throw new Error('grpc.max_message_size must be at least 1MB');
}

Prevention

When it happens

Trigger: Setting `grpc.max_message_size` in the node config to a value below 1MB (e.g. `512KB` or `0`) and starting the node or validating the config.

Common situations: Attempting to shrink memory footprint by lowering the gRPC buffer too aggressively; typo'd units (e.g. `1MB` written as `1KB`); copying a config from another project with smaller limits.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/47586af41d2cca82. Report an issue: GitHub.

Appendix: source

Thrown at quickwit/quickwit-config/src/node_config/mod.rs:130

    // should be idle before sending a keepalive ping.
    #[serde(default = "default_http2_keep_alive_interval")]
    pub interval: HumanDuration,

    // Set the HTTP/2 KEEP_ALIVE_TIMEOUT. This is the time to wait for an ACK
    // after sending a keepalive ping. If the server doesn't respond within
    // this time, the connection might be considered dead.
    // Tonic uses hyper's default (20 seconds) if not set.
    #[serde(default = "default_keep_alive_timeout")]
    pub timeout: HumanDuration,
}

impl GrpcConfig {
    fn default_max_message_size() -> ByteSize {
        ByteSize::mib(20)
    }

    pub fn validate(&self) -> anyhow::Result<()> {
        ensure!(
            self.max_message_size >= ByteSize::mb(1),
            "max gRPC message size (`grpc.max_message_size`) must be at least 1MB, got `{}`",
            self.max_message_size
        );
        if let Some(tls_config) = &self.tls_config {
            tls_config.validate()?;
        }
        ensure!(
            !(self.max_connection_age_grace.is_some() && self.max_connection_age.is_none()),
            "`grpc.max_connection_age_grace` requires `grpc.max_connection_age` to be set"
        );
        Ok(())
    }
}

impl Default for GrpcConfig {
    fn default() -> Self {
        Self {

View on GitHub (pinned to a39730c5cd)