serde-rs/json · error

no entry found for key

Error message

no entry found for key

What it means

This is a deliberate panic from serde_json's IndexMut impl for Map<String, Value> at src/map.rs:479, which calls self.map.get_mut(index).expect("no entry found for key"). Mutably indexing a Map with a key that is absent is treated like indexing a Vec out of bounds: there is no valid place to write, so the process panics rather than silently inserting or returning a default. It is by design that Map implements IndexMut (unlike std HashMap/BTreeMap), so the indexing operator map["k"] = v is only safe when the key already exists; for insert-or-update you must use the entry/insert API. The panic message is the literal string passed to expect.

Solutions

  1. Replace the mutable index assignment map["k"] = v with map.insert("k".to_owned(), v), which inserts if absent and overwrites if present.
  2. If you only want to update an existing entry, guard with map.get_mut("k") and act on the Option<&mut Value>, or use the entry API: map.entry("k".to_owned()).or_insert(default).
  3. Check presence first with map.contains_key("k") and handle the absent case explicitly rather than letting indexing panic.
  4. When the key is dynamic/external, normalize and validate it (trim, casing, allow-list) before using it as an index.
  5. Enable clippy (clippy::indexing_slicing) and review any map[k] = sites against a known key set.

Example fix

// before
let mut obj = serde_json::Map::new();
obj["missing"] = serde_json::json!(42); // panics: no entry found for key

// after
obj.insert("missing".to_owned(), serde_json::json!(42));
// or, update-only without panicking:
if let Some(slot) = obj.get_mut("missing") {
    *slot = serde_json::json!(42);
}
Defensive patterns

Strategy: validation

Validate before calling

// Check before mutating via [] to avoid the panic at src/map.rs:479.
fn set_or_skip(map: &mut serde_json::Map<String, serde_json::Value>,
               key: &str, val: serde_json::Value) {
    if map.contains_key(key) {
        map[key] = val;
    } else {
        // decide: insert, log, or skip
        map.insert(key.to_owned(), val);
    }
}

// Prefer the entry API for insert-or-update in one call:
// map.entry(key.to_owned()).or_insert(default_value);

Type guard

// Not a type-narrowing issue; the guard is key presence, not a type.
// Helper that returns Option so the caller handles absence explicitly:
fn get_slot<'a>(map: &'a mut serde_json::Map<String, serde_json::Value>,
               key: &str) -> Option<&'a mut serde_json::Value> {
    map.get_mut(key)
}

Try / catch

// Rust: panics are not Result. Avoid catch_unwind for control flow; validate instead.
// Last-resort isolation (e.g. running untrusted config transforms):
let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    map["maybe_absent"] = serde_json::json!(1);
}));
if outcome.is_err() { /* key was absent: handle */ }

Prevention

When it happens

Trigger: Calling map["someKey"] = serde_json::Value::Null (or any assignment through []) when "someKey" is not present in the Map. Triggered by IndexMut::index_mut at src/map.rs:478-480 any time get_mut returns None — e.g. the key was never inserted, was removed, or a typo'd/dynamic key (from env vars, HTTP request data, or config files) does not match any existing key.

Common situations: Building JSON output where a field name comes from external/untrusted input (request bodies, env vars) and is assumed to exist. Assuming a parsed JSON object always contains a key that the source occasionally omits. Refactoring that renames a field in one place but not the indexing site. Hot-path code that switched from map.get_mut to the [] sugar for brevity. Tests passing because the fixture always had the key, then panicking in production on a sparser document.

Related errors


AI-assisted analysis of serde-rs/json@afdf6fc672 (2026-08-08). Data as JSON: /api/errors/4433e25861dd3383. Report an issue: GitHub.

Appendix: source

Thrown at src/map.rs:479

/// Mutably access an element of this map. Panics if the given key is not
/// present in the map.
///
/// ```
/// # use serde_json::json;
/// #
/// # let mut map = serde_json::Map::new();
/// # map.insert("key".to_owned(), serde_json::Value::Null);
/// #
/// map["key"] = json!("value");
/// ```
impl<Q> ops::IndexMut<&Q> for Map<String, Value>
where
    String: Borrow<Q>,
    Q: ?Sized + Ord + Eq + Hash,
{
    fn index_mut(&mut self, index: &Q) -> &mut Value {
        self.map.get_mut(index).expect("no entry found for key")
    }
}

impl Debug for Map<String, Value> {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.map.fmt(formatter)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl serde::ser::Serialize for Map<String, Value> {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        use serde::ser::SerializeMap;

View on GitHub (pinned to afdf6fc672)