vectordotdev/vector · error
schema metadata must always be an object
Error message
schema metadata must always be an object
What it means
`set_schema_metadata_attr_str` inserts a metadata entry into a schema object's extensions and then asserts it is a JSON object before inserting the key. The panic fires when the existing metadata extension value is not a JSON object (e.g. it is a string, number, or array), so `as_object_mut()` returns `None`.
Solutions
- Check any custom `Configurable` implementations for code writing the `metadata` extension key directly and make them write a JSON object
- Ensure all crates in the workspace use the same vector-config version so the metadata convention matches
- Reproduce with a minimal config schema and inspect the generated extensions map before the visitor runs
- Reset to stock vector-config types to confirm the bug is in custom code
Example fix
// before
metadata.extensions.insert(constants::METADATA.to_string(), Value::String("my field".into()));
// after
metadata.extensions.insert(constants::METADATA.to_string(), json!({})); Defensive patterns
Strategy: type-guard
Validate before calling
fn ensure_metadata_object(extensions: &Map<String, Value>) -> Result<(), String> {
match extensions.get(constants::METADATA) {
Some(v) if !v.is_object() => Err(format!("metadata extension must be an object, got {v}")),
_ => Ok(()),
}
} Type guard
fn as_metadata_object(v: &Value) -> Option<&serde_json::Map<String, Value>> { v.as_object() } Try / catch
let metadata_map = metadata.as_object_mut().ok_or_else(||
anyhow::anyhow!("schema metadata extension is not a JSON object"))?; Prevention
- Always write the `metadata` extension key as a JSON object in custom Configurable impls
- Use vector-config's helpers (set_schema_metadata_attr_str) instead of touching extensions directly
- Run schema-generation unit tests for every custom Configurable type
When it happens
Trigger: A schema's extensions map already contains a `metadata` key whose value is not a JSON object, then a visitor such as `visit_schema_object` calls `set_schema_metadata_attr_str` to add a human-readable name; or a custom `Configurable` type writes `constants::METADATA` as a non-object value.
Common situations: Hand-rolled `Configurable` implementations writing malformed custom attributes into schema metadata; merging schemas generated by different schemars/vector-config versions where the metadata convention differs.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- all-of subschemas must be present here
- Could not convert concurrency to JSON
- Could not convert HTTP status code to JSON
- Could not convert number to JSON
- Could not convert time zone to JSON
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/8ecfd4fc1fc8e024.
Report an issue: GitHub.
Appendix: source
Thrown at lib/vector-config/src/schema/visitors/human_name.rs:100
}
fn get_schema_metadata_attr_str<'a>(schema: &'a SchemaObject, key: &str) -> Option<&'a str> {
schema
.extensions
.get(constants::METADATA)
.and_then(|metadata| metadata.get(key))
.and_then(|value| value.as_str())
}
fn set_schema_metadata_attr_str(schema: &mut SchemaObject, key: &str, value: String) {
let metadata = schema
.extensions
.entry(constants::METADATA.to_string())
.or_insert_with(|| Value::Object(serde_json::Map::new()));
let metadata_map = metadata
.as_object_mut()
.expect("schema metadata must always be an object");
metadata_map.insert(key.to_string(), Value::String(value));
}
#[cfg(test)]
mod tests {
use serde_json::json;
use vector_config_common::schema::visit::Visitor;
use super::GenerateHumanFriendlyNameVisitor;
use crate::schema::visitors::test::{as_schema, assert_schemas_eq};
#[test]
fn logical_name() {
let mut actual_schema = as_schema(json!({
"type": "string",
"_metadata": {
"logical_name": "LogToMetric"
}View on GitHub (pinned to bdb87aeaa4)