{"record":{"id":"4433e25861dd3383","repo":"serde-rs/json","slug":"no-entry-found-for-key","errorCode":null,"errorMessage":"no entry found for key","messagePattern":"no entry found for key","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/map.rs","lineNumber":479,"sourceCode":"\n/// Mutably access an element of this map. Panics if the given key is not\n/// present in the map.\n///\n/// ```\n/// # use serde_json::json;\n/// #\n/// # let mut map = serde_json::Map::new();\n/// # map.insert(\"key\".to_owned(), serde_json::Value::Null);\n/// #\n/// map[\"key\"] = json!(\"value\");\n/// ```\nimpl<Q> ops::IndexMut<&Q> for Map<String, Value>\nwhere\n    String: Borrow<Q>,\n    Q: ?Sized + Ord + Eq + Hash,\n{\n    fn index_mut(&mut self, index: &Q) -> &mut Value {\n        self.map.get_mut(index).expect(\"no entry found for key\")\n    }\n}\n\nimpl Debug for Map<String, Value> {\n    #[inline]\n    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {\n        self.map.fmt(formatter)\n    }\n}\n\n#[cfg(any(feature = \"std\", feature = \"alloc\"))]\nimpl serde::ser::Serialize for Map<String, Value> {\n    #[inline]\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::ser::Serializer,\n    {\n        use serde::ser::SerializeMap;","sourceCodeStart":461,"sourceCodeEnd":497,"githubUrl":"https://github.com/serde-rs/json/blob/afdf6fc67247dd7fa4fcde1381e6ecc6bcc7a30e/src/map.rs#L461-L497","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Replace the mutable index assignment map[\"k\"] = v with map.insert(\"k\".to_owned(), v), which inserts if absent and overwrites if present.","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).","Check presence first with map.contains_key(\"k\") and handle the absent case explicitly rather than letting indexing panic.","When the key is dynamic/external, normalize and validate it (trim, casing, allow-list) before using it as an index.","Enable clippy (clippy::indexing_slicing) and review any map[k] = sites against a known key set."],"exampleFix":"// before\nlet mut obj = serde_json::Map::new();\nobj[\"missing\"] = serde_json::json!(42); // panics: no entry found for key\n\n// after\nobj.insert(\"missing\".to_owned(), serde_json::json!(42));\n// or, update-only without panicking:\nif let Some(slot) = obj.get_mut(\"missing\") {\n    *slot = serde_json::json!(42);\n}","handlingStrategy":"validation","validationCode":"// Check before mutating via [] to avoid the panic at src/map.rs:479.\nfn set_or_skip(map: &mut serde_json::Map<String, serde_json::Value>,\n               key: &str, val: serde_json::Value) {\n    if map.contains_key(key) {\n        map[key] = val;\n    } else {\n        // decide: insert, log, or skip\n        map.insert(key.to_owned(), val);\n    }\n}\n\n// Prefer the entry API for insert-or-update in one call:\n// map.entry(key.to_owned()).or_insert(default_value);","typeGuard":"// Not a type-narrowing issue; the guard is key presence, not a type.\n// Helper that returns Option so the caller handles absence explicitly:\nfn get_slot<'a>(map: &'a mut serde_json::Map<String, serde_json::Value>,\n               key: &str) -> Option<&'a mut serde_json::Value> {\n    map.get_mut(key)\n}","tryCatchPattern":"// Rust: panics are not Result. Avoid catch_unwind for control flow; validate instead.\n// Last-resort isolation (e.g. running untrusted config transforms):\nlet outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    map[\"maybe_absent\"] = serde_json::json!(1);\n}));\nif outcome.is_err() { /* key was absent: handle */ }","preventionTips":["Prefer Map::insert / Map::entry over the [] = sugar whenever the key may be absent.","Treat keys derived from external input (env, request, config) as untrusted: normalize and validate before indexing.","Enable clippy::indexing_slicing to flag [] usage on maps for review.","Write a unit test that exercises the absent-key path, not just the present-key fixture.","Keep a documented allow-list of expected object keys near the indexing site."],"tags":["serde-json","map","indexing","panic","runtime"],"backgroundTag":null,"analyzedSha":"afdf6fc67247dd7fa4fcde1381e6ecc6bcc7a30e","analyzedAt":"2026-08-08T07:08:57.171Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}