cloudflare/pingora · error · std::io::Error

dial9 max_file_size must be greater than zero

Error message

dial9 max_file_size must be greater than zero

What it means

build_dial9_runtime() in pingora-runtime validates Dial9RuntimeOpts before constructing the dial9 traced Tokio runtime that writes rotating trace files. max_file_size is the per-file cap of the rotating trace writer, and 0 is rejected up front with ErrorKind::InvalidInput. The error is returned (not a panic) at runtime construction time, so it fails fast during startup.

Source

Thrown at pingora-runtime/src/lib.rs:319

    #[cfg(not(tokio_unstable))]
    let _ = (builder, opts);
}

#[cfg(feature = "dial9")]
fn build_dial9_runtime(
    builder: Builder,
    runtime_name: &str,
    opts: &Dial9RuntimeOpts,
) -> std::io::Result<(
    tokio::runtime::Runtime,
    dial9_tokio_telemetry::telemetry::TelemetryGuard,
)> {
    use dial9_tokio_telemetry::telemetry::{RotatingWriter, TracedRuntime};
    use std::io::{Error, ErrorKind};

    if opts.max_file_size == 0 {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "dial9 max_file_size must be greater than zero",
        ));
    }
    if opts.max_total_size == 0 {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "dial9 max_total_size must be greater than zero",
        ));
    }
    if opts.max_file_size > opts.max_total_size {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "dial9 max_file_size must be less than or equal to max_total_size",
        ));
    }
    if opts.worker_poll_interval == Some(Duration::ZERO) {
        return Err(Error::new(

View on GitHub (pinned to 0046038bd4)

Solutions

  1. Set max_file_size to a positive size in bytes (e.g. 64 * 1024 * 1024 per trace file)
  2. Satisfy the sibling checks in the same validation block: max_total_size > 0, max_file_size <= max_total_size, worker_poll_interval None or positive
  3. Populate these fields from a validated config loader instead of raw optional deserialization

Example fix

// before
let opts = Dial9RuntimeOpts { max_file_size: 0, max_total_size: 1 << 30, ..Default::default() };

// after
let opts = Dial9RuntimeOpts { max_file_size: 64 << 20, max_total_size: 1 << 30, ..Default::default() };
Defensive patterns

Strategy: validation

Validate before calling

// Mirror the library's checks at config-load time
fn validate_dial9(opts: &Dial9RuntimeOpts) -> std::io::Result<()> {
    if opts.max_file_size == 0 {
        return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "max_file_size must be > 0"));
    }
    if opts.max_total_size == 0 {
        return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "max_total_size must be > 0"));
    }
    if opts.max_file_size > opts.max_total_size {
        return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "max_file_size must be <= max_total_size"));
    }
    Ok(())
}

Prevention

When it happens

Trigger: Building the dial9 traced runtime through pingora-runtime with Dial9RuntimeOpts { max_file_size: 0, .. }, typically because the field was left at its zero default or a config file supplied 0.

Common situations: Wiring Dial9RuntimeOpts from YAML/env where max_file_size was forgotten; a config schema change that stopped populating the field; copy-pasting an options struct literal with placeholder zeros.

Related errors


AI-assisted analysis of cloudflare/pingora@0046038bd4 (2026-08-16). Data as JSON: /api/errors/f10ceca4da7bc19d. Report an issue: GitHub.