vectordotdev/vector · error

Path must end with a key.

Error message

Path must end with a key.

What it means

`Renderer::write` in the docs-renderer splits a slash-delimited path and pops the last segment as the target map key; it panics if there is no such segment. A path with no trailing key (e.g. `"/"` or `""`) has nowhere to write, so the operation is invalid by contract — paths must point at a concrete key below the root.

Solutions

  1. Ensure every path passed to `write` includes at least one segment after the leading `/` (e.g. `/section/key` not `/section` or `/`)
  2. Guard dynamic path construction: skip or special-case entries whose computed path ends at the root
  3. Validate/trim paths before calling and reject root-only paths early
  4. If the path should replace the whole document, use the appropriate root-level API instead of `write`

Example fix

// before
renderer.write("/", value);
// after
if path_segments.len() >= 2 {
    renderer.write(&path, value);
}
Defensive patterns

Strategy: validation

Validate before calling

fn is_writable_path(path: &str) -> bool {
    path.split('/').any(|seg| !seg.is_empty())
}

Prevention

When it happens

Trigger: Calling `write` with a path that has no key segment after splitting on `/`: `"/"` (root only), an empty string, or a path consisting solely of slashes.

Common situations: Typically a bug in docs-generation code that computes paths dynamically, e.g. joining components and producing a bare `/` for top-level entries, or template/config data missing a section name.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/882e6582b993d4b8. Report an issue: GitHub.

Appendix: source

Thrown at lib/docs-renderer/src/renderer.rs:73

    ///
    /// # Panics
    ///
    /// If the path does not start with a forward slash, this method will panic. Likewise, if the
    /// path is _only_ a forward slash (aka there is no segment to describe the key within the
    /// object to write the value to), this method will panic.
    ///
    /// If any nested object within the path does not yet exist, it will be created. If any segment,
    /// other than the leaf segment, points to a value that is not an object/map, this method will
    /// panic.
    pub fn write<V: Into<Value>>(&mut self, path: &str, value: V) {
        if !path.starts_with('/') {
            panic!("Paths must always start with a leading forward slash (`/`).");
        }

        self.with_mut_object(|map| {
            // Split the path, and take the last element as the actual map key to write to.
            let mut segments = path.split('/').collect::<VecDeque<_>>();
            let key = segments.pop_back().expect("Path must end with a key.");

            // Iterate over the remaining elements, traversing into the root object one level at a
            // time, based on using `token` as the map key. If there's no map at the given key,
            // we'll create one. If there's something other than a map, we'll panic.
            let mut destination = map;
            while let Some(segment) = segments.pop_front() {
                if destination.contains_key(segment) {
                    match destination.get_mut(segment) {
                        Some(Value::Object(next)) => {
                            destination = next;
                            continue;
                        }
                        Some(_) => {
                            panic!("Only leaf nodes should be allowed to be non-object values.")
                        }
                        None => unreachable!("Already asserted that the given key exists."),
                    }
                } else {

View on GitHub (pinned to bdb87aeaa4)