{"record":{"id":"8f4de04f556b5702","repo":"astrid-runtime/astrid","slug":"metadata-region-name-too-long","errorCode":null,"errorMessage":"metadata region name too long","messagePattern":"metadata region name too long","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage/src/volume/hosted/mod.rs","lineNumber":518,"sourceCode":"        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, \"too many metadata mutations\"))?;\n    let mut output = Vec::new();\n    output.extend_from_slice(&count.to_le_bytes());\n    for mutation in mutations {\n        let (kind, source, destination) = match mutation {\n            VolumeMetadataMutation::Rename {\n                source,\n                destination,\n            } => (1_u8, source, destination),\n            VolumeMetadataMutation::Replace {\n                source,\n                destination,\n            } => (2_u8, source, destination),\n        };\n        output.push(kind);\n        for region in [source, destination] {\n            let bytes = region.as_str().as_bytes();\n            let length = u16::try_from(bytes.len()).map_err(|_| {\n                io::Error::new(io::ErrorKind::InvalidInput, \"metadata region name too long\")\n            })?;\n            output.extend_from_slice(&length.to_le_bytes());\n            output.extend_from_slice(bytes);\n        }\n    }\n    Ok(output)\n}\n\nfn decode_metadata_mutations(bytes: &[u8]) -> io::Result<Vec<VolumeMetadataMutation>> {\n    let mut cursor = 0_usize;\n    let count = usize::from(read_u16(bytes, &mut cursor)?);\n    if count == 0 || count > MAX_METADATA_MUTATIONS {\n        return Err(invalid_transition(\"invalid metadata transaction count\"));\n    }\n    let mut mutations = Vec::with_capacity(count);\n    for _ in 0..count {\n        let kind = *bytes\n            .get(cursor)","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage/src/volume/hosted/mod.rs#L500-L536","documentation":"Each region name in a metadata mutation is length-prefixed with a u16, so a region name may be at most 65535 bytes. Longer names cannot be encoded and are rejected with InvalidInput. Note the encoder emits both source and destination for every mutation, so either may trip this.","triggerScenarios":"Encoding a Rename (or other two-region) mutation whose source or destination VolumeRegion string exceeds 65535 bytes when UTF-8 encoded.","commonSituations":"Programmatically generated region names (hashes, templated paths) that grew unbounded; user-supplied names concatenated with long prefixes; fuzzing or property tests feeding huge strings.","solutions":["Validate region name length (e.g. keep it well under 64 KiB, ideally a small fixed cap) when constructing VolumeRegion::new.","Truncate or reject over-long names at the API boundary that builds mutations.","If names legitimately need to be long, store an identifier/alias in the region name instead of the full payload."],"exampleFix":"// before\nlet region = VolumeRegion::new(generated_name);\n// after\nassert!(generated_name.len() <= u16::MAX as usize, \"region name too long\");\nlet region = VolumeRegion::new(generated_name);","handlingStrategy":"validation","validationCode":"fn region_name_encodable(name: &str) -> bool {\n    name.as_bytes().len() <= u16::MAX as usize\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Enforce a small name-length cap when constructing VolumeRegion.","Validate user- or generator-supplied names at the boundary that builds mutations.","Avoid embedding unbounded payloads (hashes, paths) in region names."],"tags":["storage","metadata","validation","encoding"],"backgroundTag":"value-out-of-range","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}