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

Gemini CLI model_provider received non-finite temperature va

Error message

Gemini CLI model_provider received non-finite temperature value

What it means

GeminiCliModelProvider::validate_temperature rejects NaN and +/-inf temperatures before spawning the CLI. Only finite f64 values can be compared against the supported set, so non-finite input is a caller bug - usually arithmetic or deserialized config producing NaN upstream.

Source

Thrown at crates/zeroclaw-providers/src/gemini_cli.rs:89

            binary_path: None,
        }
    }

    /// Returns true if the model argument should be forwarded to the CLI.
    fn should_forward_model(model: &str) -> bool {
        let trimmed = model.trim();
        !trimmed.is_empty() && trimmed != DEFAULT_MODEL_MARKER
    }

    fn supports_temperature(temperature: f64) -> bool {
        GEMINI_CLI_SUPPORTED_TEMPERATURES
            .iter()
            .any(|v| (temperature - v).abs() < TEMP_EPSILON)
    }

    fn validate_temperature(temperature: f64) -> anyhow::Result<()> {
        if !temperature.is_finite() {
            anyhow::bail!("Gemini CLI model_provider received non-finite temperature value");
        }
        if !Self::supports_temperature(temperature) {
            anyhow::bail!(
                "temperature unsupported by Gemini CLI: {temperature}. \
                 Supported values: 0.7 or 1.0"
            );
        }
        Ok(())
    }

    fn redact_stderr(stderr: &[u8]) -> String {
        let text = String::from_utf8_lossy(stderr);
        let trimmed = text.trim();
        if trimmed.is_empty() {
            return String::new();
        }
        if trimmed.chars().count() <= MAX_GEMINI_CLI_STDERR_CHARS {
            return trimmed.to_string();

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Sanitize at the source: reject or clamp non-finite values before they reach the provider
  2. Fix the arithmetic producing NaN (guard divisions, validate deserialized floats)
  3. Pass None to use the CLI default instead of a bogus value

Example fix

// before
let temperature = base * scale; // may be NaN
let text = provider.chat_with_system(None, prompt, model, Some(temperature)).await?;

// after
let temperature = (base * scale).is_finite().then_some(base * scale);
let text = provider.chat_with_system(None, prompt, model, temperature).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn safe_temperature(t: Option<f64>) -> anyhow::Result<Option<f64>> {
    match t {
        Some(v) if v.is_finite() => Ok(Some(v)),
        Some(_) => anyhow::bail!("temperature must be finite (got NaN/inf)"),
        None => Ok(None),
    }
}

Type guard

fn temperature_is_finite(t: f64) -> bool { t.is_finite() }

Try / catch

if let Err(e) = provider.chat_with_system(None, prompt, model, Some(t)).await {
    if e.to_string().contains("non-finite temperature") {
        // programmer error: fix the value source, do not retry
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Passing Some(f64::NAN) or Some(f64::INFINITY) as temperature to chat_with_system/chat_with_history; computing temperature via a division that can yield 0/0; a TOML/JSON config containing nan or inf.

Common situations: temperature = nan in config files; dynamic formulas like base * factor where factor is NaN; temperatures forwarded from another provider's response without sanitization.

Related errors


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