{"record":{"id":"09a49fef633170b0","repo":"pydantic/monty","slug":"stringid-overflow","errorCode":null,"errorMessage":"StringId overflow","messagePattern":"StringId overflow","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/monty/src/intern.rs","lineNumber":1447,"sourceCode":"    pub fn get_str(&self, id: StringId) -> &str {\n        get_str(&self.strings, id)\n    }\n}\n\n/// Interns `s` into a `string_map`/`strings` pair, shared by [`InternerBuilder`]\n/// and [`Interns`] so both tables allocate ids identically.\n///\n/// Single-ASCII and [`StaticStrings`] values resolve to their reserved ids\n/// without touching the pool; everything else is deduplicated via `string_map`.\nfn intern_str(string_map: &mut AHashMap<String, StringId>, strings: &mut Vec<WithHash<String>>, s: &str) -> StringId {\n    if s.len() == 1 {\n        StringId::from_ascii(s.as_bytes()[0])\n    } else if let Ok(ss) = StaticStrings::from_str(s) {\n        ss.into()\n    } else {\n        *string_map.entry(s.to_owned()).or_insert_with(|| {\n            let string_id = strings.len() + INTERN_STRING_ID_OFFSET;\n            let id = StringId(string_id.try_into().expect(\"StringId overflow\"));\n            strings.push(WithHash::for_str(s.to_owned()));\n            id\n        })\n    }\n}\n\n/// Reverse of [`get_str`]: the `StringId` for `s`, or `None` if never interned.\n///\n/// Single ASCII char and [`StaticStrings`] ids live in reserved slot ranges\n/// below [`INTERN_STRING_ID_OFFSET`], never in `string_map` — the cheap\n/// branches come first.\nfn get_string_id_by_name(string_map: &AHashMap<String, StringId>, s: &str) -> Option<StringId> {\n    if s.len() == 1 {\n        Some(StringId::from_ascii(s.as_bytes()[0]))\n    } else if let Ok(ss) = StaticStrings::from_str(s) {\n        Some(ss.into())\n    } else {\n        string_map.get(s).copied()","sourceCodeStart":1429,"sourceCodeEnd":1465,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/intern.rs#L1429-L1465","documentation":"While interning a string, `intern_str` computes a new `StringId` from `strings.len() + INTERN_STRING_ID_OFFSET` and converts it to the ID's backing integer with `expect`. If the count plus offset exceeds the ID capacity, this panics. It guards the interpreter's assumption that all strings in a compilation fit the ID space.","triggerScenarios":"Interning a string when the number of already-interned strings plus `INTERN_STRING_ID_OFFSET` exceeds the `StringId` backing integer's maximum (e.g. > u32::MAX strings in one table).","commonSituations":"Only reachable with billions of distinct string literals/identifiers in one intern table, or a leaked/reused-table bug causing unbounded growth.","solutions":["Reuse or reset the InternTable per compilation so the string count stays bounded.","Widen `StringId` (e.g. to u64) if the workload legitimately needs more IDs.","Treat as a bug report if triggered by realistic input."],"exampleFix":"// before\nlet id = StringId(string_id.try_into().expect(\"StringId overflow\"));\n// after\nlet id = StringId(u32::try_from(string_id).map_err(|_| CompileError::TooManyInternedStrings)?);","handlingStrategy":"validation","validationCode":"assert!(intern_table.string_count() + INTERN_STRING_ID_OFFSET < u32::MAX as usize, \"StringId space exhausted\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep per-compilation string volume bounded","Reuse intern tables instead of growing one indefinitely","Report occurrences with the offending source"],"tags":["rust","panic","interning"],"backgroundTag":"internal-invariant-violation","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}