linera-io/linera-protocol · error · anyhow
Invalid blob ID: {s}
Error message
Invalid blob ID: {s} What it means
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.
Source
Thrown at linera-base/src/identifiers.rs:352
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.blob_type, self.hash)?;
Ok(())
}
}
impl std::str::FromStr for BlobId {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts = s.split(':').collect::<Vec<_>>();
if parts.len() == 2 {
let blob_type = BlobType::from_str(parts[0]).context("Invalid BlobType!")?;
Ok(BlobId {
hash: CryptoHash::from_str(parts[1]).context("Invalid hash!")?,
blob_type,
})
} else {
Err(anyhow!("Invalid blob ID: {s}"))
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename = "BlobId")]
struct BlobIdHelper {
hash: CryptoHash,
blob_type: BlobType,
}
impl Serialize for BlobId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
serializer.serialize_str(&self.to_string())View on GitHub (pinned to 6c226ddcb3)
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 ':'
Example fix
// before: bare hash has no 'type:' prefix
let blob_id: BlobId = hash_str.parse()?; // Err: Invalid blob ID: 6ab0f8e8...
// after: type-prefixed Display form
let blob_id: BlobId = format!("Data:{hash_str}").parse()?; Defensive patterns
Strategy: type-guard
Validate before calling
fn looks_like_blob_id(s: &str) -> bool {
let Some((ty, hash)) = s.split_once(':') else { return false };
!ty.is_empty()
&& hash.len() == 64
&& hash.bytes().all(|b| b.is_ascii_hexdigit())
} Type guard
fn parse_blob_id(s: &str) -> Option<BlobId> {
s.parse().ok()
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid parsing of GenericApplicationId
- Invalid stream ID: {s}
- Invalid address value: {s}
- Failed to obtain a port
- GITHUB_PR_NUMBER is not a valid number: {pr_string}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/f4f393970407c922.
Report an issue: GitHub.