Hmbown/CodeWhale · error · anyhow::Error

duration {s:?} resolved to zero seconds

Error message

duration {s:?} resolved to zero seconds

What it means

The duration string parsed successfully but every component summed to zero seconds, which parse_duration_secs rejects because a zero-length window is meaningless for the metrics cutoff computation. A trailing bare number is treated as seconds, so "0" also lands here.

Source

Thrown at crates/cli/src/metrics.rs:102

                    'h' => 3_600,
                    'm' => 60,
                    's' => 1,
                    _ => unreachable!(),
                };
                total += n * factor;
            }
            _ => anyhow::bail!("unrecognised character {ch:?} in duration {s:?}"),
        }
    }

    if !num_buf.is_empty() {
        // Trailing bare number — treat as seconds.
        let n: i64 = num_buf.parse()?;
        total += n;
    }

    if total == 0 {
        anyhow::bail!("duration {s:?} resolved to zero seconds");
    }

    Ok(total)
}

// ──────────────────────────────────────────────────────────────────────────────
// Rollup data model
// ──────────────────────────────────────────────────────────────────────────────

/// Per-tool aggregated counters.
#[derive(Debug, Default, serde::Serialize)]
pub struct ToolStats {
    pub calls: u64,
    /// Calls that were auto-approved (no prompt required).
    pub auto_approved: u64,
    /// Calls that required a manual prompt.
    pub prompted: u64,
    /// Total elapsed ms (from events that carry this field).

View on GitHub (pinned to 8880682c63)

Solutions

  1. Choose an explicit non-zero window, e.g. "1d" or "30d"
  2. Guard scripted variables so an empty/unset value becomes a sane default instead of "0"
  3. Compute windows upstream and pass a concrete non-zero duration

Example fix

# before
 codewhale metrics --since "${SINCE:-0}"   # error: duration "0" resolved to zero seconds

# after
 codewhale metrics --since "${SINCE:-7d}"
Defensive patterns

Strategy: validation

Validate before calling

// Reject zero-valued windows in your wrapper before invoking the CLI:
fn nonzero_duration_secs(s: &str) -> Option<i64> {
    let total = parse_duration_secs(s).ok()?;
    (total > 0).then_some(total)
}

Prevention

When it happens

Trigger: Passing "0s", "0", "00m00s", or a --since flag whose variable expanded to a bare zero.

Common situations: Scripts intending "all history" by passing 0 — not supported; empty-variable defaults coercing to "0"; computed windows rounding down to zero.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/62adc2d2df419a38. Report an issue: GitHub.