vectordotdev/vector · error
Could not convert duration to JSON
Error message
Could not convert duration to JSON
What it means
ToValue for std::time::Duration serializes the duration with serde_json::to_value and expects success. serde_json::to_value can only fail for non-string-keyed maps or unsupported types, so this panic indicates a serde_json serialization invariant was violated while converting a Duration to a config Value.
Solutions
- Check for a custom Serialize implementation for Duration (or a wrapper type) that can fail; make it infallible.
- Ensure no serde_json serializer feature flags (e.g. arbitrary_precision mismatches) differ between build units.
- Verify no manual ToValue impl produces a non-JSON-serializable intermediate value.
- Update serde_json/vector-config to a matching version so Duration serialization behaves as expected.
Example fix
// before
impl Serialize for MyDurationWrapper {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> { Err(serde::ser::Error::custom("unsupported")) }
}
// after
impl Serialize for MyDurationWrapper {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> { self.as_secs_f64().serialize(s) }
} Defensive patterns
Strategy: type-guard
Type guard
fn duration_to_value(d: &Duration) -> Option<Value> {
serde_json::to_value(d).ok()
} Try / catch
// Rust has no catch; avoid expect by handling Result
let value = serde_json::to_value(duration).unwrap_or_else(|e| {
eprintln!("duration serialization failed: {e}");
Value::Null
}); Prevention
- Do not implement fallible custom Serialize impls for Duration wrappers.
- Keep serde/serde_json versions aligned across workspace crates.
- Prefer storing durations as u64 millis/secs in config structures.
When it happens
Trigger: Calling to_value() on a config struct containing a Duration field where serde_json serialization unexpectedly fails (e.g. a custom Serialize impl returning an error, or serialization of a map with non-string keys nested in the duration wrapper).
Common situations: Building config schemas or merging default configs that include Duration fields; rare in practice because Duration serializes deterministically — usually seen when someone adds a custom Serializer/Serializer impl around Duration.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- Could not convert HTTP status code to JSON
- Could not convert time zone to JSON
- Could not convert TOML value to JSON
- Unable to serialize VRL value
- Could not convert concurrency to JSON
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/535736b06c7a49d2.
Report an issue: GitHub.
Appendix: source
Thrown at lib/vector-config/src/stdlib.rs:501
fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
let mut properties = IndexMap::default();
properties.insert("secs".into(), generate_number_schema::<u64>());
properties.insert("nsecs".into(), generate_number_schema::<u32>());
let mut required = BTreeSet::default();
required.insert("secs".into());
required.insert("nsecs".into());
Ok(crate::schema::generate_struct_schema(
properties, required, None,
))
}
}
impl ToValue for Duration {
fn to_value(&self) -> Value {
serde_json::to_value(self).expect("Could not convert duration to JSON")
}
}
View on GitHub (pinned to bdb87aeaa4)