linera-io/linera-protocol · error · anyhow
Invalid blob ID
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.
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.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- Invalid parsing of GenericApplicationId
- Invalid stream ID
- Invalid address value
- failed to load data blob bytes from
- Failed to obtain a port
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/f4f393970407c922.
Report an issue: GitHub.
Appendix: 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)