zeroclaw-labs/zeroclaw · error · anyhow::Error
findings[{}].cvss_score must be between 0.0 and 10.0, got {}
Error message
findings[{}].cvss_score must be between 0.0 and 10.0, got {} What it means
parse_vulnerability_json deserializes the report with serde, then enforces 0.0 <= findings[i].cvss_score <= 10.0 for every finding (vulnerability.rs:83-91). The index in the message identifies the offending finding. NaN also fails, because the range check is false for NaN.
Source
Thrown at crates/zeroclaw-runtime/src/security/vulnerability.rs:86
}
}
pub fn parse_vulnerability_json(json_str: &str) -> anyhow::Result<VulnerabilityReport> {
let report: VulnerabilityReport = serde_json::from_str(json_str).map_err(|e| {
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({"error": format!("{}", e)})),
"vulnerability report rejected: JSON parse failed"
);
anyhow::Error::msg(format!("Failed to parse vulnerability report: {e}"))
})?;
for (i, finding) in report.findings.iter().enumerate() {
if !(0.0..=10.0).contains(&finding.cvss_score) {
anyhow::bail!(
"findings[{}].cvss_score must be between 0.0 and 10.0, got {}",
i,
finding.cvss_score
);
}
}
Ok(report)
}
/// Generate a summary of the vulnerability report.
pub fn generate_summary(report: &VulnerabilityReport) -> String {
if report.findings.is_empty() {
return format!(
"Vulnerability scan by {} on {}: No findings.",
report.scanner,
report.scan_date.format("%Y-%m-%d")
);
}View on GitHub (pinned to 88bb9c8533)
Solutions
- Sanitize the source report: clamp or drop findings with sentinel scores before calling parse_vulnerability_json
- Fix the exporter so unknown scores are omitted or written as 0.0
- Pre-validate the findings array yourself if you accept untrusted scanner output
Example fix
// before
let report = parse_vulnerability_json(&raw)?;
// after: clamp sentinel scores before parsing
let mut value: serde_json::Value = serde_json::from_str(&raw)?;
if let Some(findings) = value.get_mut("findings").and_then(|f| f.as_array_mut()) {
for f in findings {
if let Some(score) = f.get("cvss_score").and_then(|s| s.as_f64()) {
if !(0.0..=10.0).contains(&score) {
f["cvss_score"] = serde_json::json!(score.clamp(0.0, 10.0));
}
}
}
}
let report = parse_vulnerability_json(&value.to_string())?; Defensive patterns
Strategy: validation
Validate before calling
fn cvss_scores_valid(json: &str) -> Result<(), String> {
let v: serde_json::Value = serde_json::from_str(json).map_err(|e| e.to_string())?;
let findings = v.get("findings").and_then(|f| f.as_array()).ok_or("missing findings")?;
for (i, f) in findings.iter().enumerate() {
let ok = f.get("cvss_score")
.and_then(|s| s.as_f64())
.map(|s| (0.0..=10.0).contains(&s))
.unwrap_or(false);
if !ok { return Err(format!("findings[{i}].cvss_score out of range")); }
}
Ok(())
} Try / catch
Catch the error and parse the 'findings[{i}]' index from the message to report the exact offending finding to the scanner operator; do not retry the same input. Prevention
- Normalize scanner output (clamp or drop sentinel scores) at ingest time
- Add contract tests containing -1, 10.1, and NaN scores
- Pin exporter versions known to emit valid CVSS v3 values
When it happens
Trigger: Feeding a report where a finding has cvss_score -1 (a common 'unknown' sentinel), 99, or NaN; the message prints the exact array index and value.
Common situations: Scanner exporters write -1 for un-scored CVEs; a CSV-to-JSON converter mangles numeric fields; hand-edited report JSON with placeholder scores.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- security.otp.cache_valid_secs must be greater than or equal
- security.otp.gated_actions[{i}] contains invalid characters:
- AgentScopedMemory refuses purge_namespace: cross-agent bulk
- memory write blocked by content scan: {kinds}
- xAI OAuth discovery returned non-HTTPS {label}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/e97aa2d42e24bf15.
Report an issue: GitHub.