{"record":{"id":"f4f393970407c922","repo":"linera-io/linera-protocol","slug":"invalid-blob-id-s","errorCode":null,"errorMessage":"Invalid blob ID: {s}","messagePattern":"Invalid blob ID: (.+?)","errorType":"validation","errorClass":"anyhow","httpStatus":null,"severity":"error","filePath":"linera-base/src/identifiers.rs","lineNumber":352,"sourceCode":"    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}:{}\", self.blob_type, self.hash)?;\n        Ok(())\n    }\n}\n\nimpl std::str::FromStr for BlobId {\n    type Err = anyhow::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let parts = s.split(':').collect::<Vec<_>>();\n        if parts.len() == 2 {\n            let blob_type = BlobType::from_str(parts[0]).context(\"Invalid BlobType!\")?;\n            Ok(BlobId {\n                hash: CryptoHash::from_str(parts[1]).context(\"Invalid hash!\")?,\n                blob_type,\n            })\n        } else {\n            Err(anyhow!(\"Invalid blob ID: {s}\"))\n        }\n    }\n}\n\n#[derive(Serialize, Deserialize)]\n#[serde(rename = \"BlobId\")]\nstruct BlobIdHelper {\n    hash: CryptoHash,\n    blob_type: BlobType,\n}\n\nimpl Serialize for BlobId {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        if serializer.is_human_readable() {\n            serializer.serialize_str(&self.to_string())","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-base/src/identifiers.rs#L334-L370","documentation":"BlobId::from_str expects exactly '<BlobType>:<CryptoHash>' (e.g. 'Data:6ab0f8e8...'). The string is split on ':' and must produce exactly 2 parts; any other part count raises this error. If the count is 2 but the type or hash is malformed, you instead get the chained 'Invalid BlobType!' or 'Invalid hash!' context errors, so this specific message means the overall shape is wrong.","triggerScenarios":"Calling \\\"...\\\".parse::<BlobId>() on a string with zero colons or two-or-more colons: a bare hash like '6ab0f8e8...', a type alone like 'Data', or a string where the hash portion itself contains ':' separators.","commonSituations":"Hand-assembling blob IDs in glue code or shell scripts; passing a blob URL or a 'type/hash' string produced by another tool; copy-paste truncation from CLI output; passing a serialized JSON object where the Display string is expected.","solutions":["Use the exact Display form: format!(\"{}:{}\", blob_type, crypto_hash)","Round-trip through BlobId::to_string() instead of building strings by hand","If your source data uses a different separator (e.g. '/'), convert it by splitting once on that separator and re-joining with ':'"],"exampleFix":"// before: bare hash has no 'type:' prefix\nlet blob_id: BlobId = hash_str.parse()?; // Err: Invalid blob ID: 6ab0f8e8...\n\n// after: type-prefixed Display form\nlet blob_id: BlobId = format!(\"Data:{hash_str}\").parse()?;","handlingStrategy":"type-guard","validationCode":"fn looks_like_blob_id(s: &str) -> bool {\n    let Some((ty, hash)) = s.split_once(':') else { return false };\n    !ty.is_empty()\n        && hash.len() == 64\n        && hash.bytes().all(|b| b.is_ascii_hexdigit())\n}","typeGuard":"fn parse_blob_id(s: &str) -> Option<BlobId> {\n    s.parse().ok()\n}","tryCatchPattern":null,"preventionTips":["Only feed BlobId::from_str strings that came from BlobId::to_string()","Validate the '<type>:<64-hex>' shape at your API boundary before parsing","Never assemble blob IDs by concatenating user input without the one-colon check"],"tags":["parsing","identifier","blob","linera-base","rust"],"backgroundTag":"invalid-identifier-format","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}