BoundaryML/baml · error · io::Error

blob digest has no prefix

Error message

blob digest has no prefix

What it means

BlobStore::path_for sharding uses the first two hex characters of the normalized digest as a subdirectory prefix. This error fires when slicing digest[..2] fails, i.e. the digest has fewer than 2 characters. In practice validate() (length 64, hex only) runs first, so this is a defensive internal invariant guard.

Solutions

  1. Ensure the digest passes normalized_digest() before computing the path; fix the caller to call validate().
  2. Check that the BlobRef construction path produces the full 64-char digest, not an empty string.
  3. If this appears with valid digests, report it — it indicates an internal invariant violation in the library.

Example fix

// before
let prefix = digest.get(..2).ok_or(...)?; // reached with digest.len() < 2
// after
let digest = blob_ref.normalized_digest()?; // validates len==64 + hex first
let prefix = &digest[..2];
Defensive patterns

Strategy: validation

Validate before calling

let digest = blob_ref.normalized_digest()?; // panics-free guard: validates len 64 + hex before path math
debug_assert!(digest.len() >= 2);

Type guard

fn has_prefix(digest: &str) -> bool { digest.len() >= 2 }

Try / catch

let path = store.path_for(&blob_ref).map_err(|e| {
    eprintln!("cannot resolve blob path: {e}");
    e
})?;

Prevention

When it happens

Trigger: path_for() with a BlobRef whose digest is shorter than 2 characters — only possible if validate/normalized_digest were bypassed or a new code path constructs the store without calling normalized_digest.

Common situations: Custom or forked code paths calling path_for with an unvalidated BlobRef, or regressions after refactoring validation order.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/2ee5557ac5ab499a. Report an issue: GitHub.

Appendix: source

Thrown at baml_language/crates/bex_events/src/value/artifact.rs:115

}

impl BlobStore {
    #[must_use]
    pub fn new(root: impl AsRef<Path>) -> Self {
        Self {
            root: root.as_ref().to_path_buf(),
        }
    }

    #[must_use]
    pub fn for_boundary_dir(boundary_dir: impl AsRef<Path>) -> Self {
        Self::new(boundary_dir.as_ref().join("blobs"))
    }

    pub fn path_for(&self, blob_ref: &BlobRef) -> io::Result<PathBuf> {
        let digest = blob_ref.normalized_digest()?;
        let prefix = digest.get(..2).ok_or_else(|| {
            io::Error::new(io::ErrorKind::InvalidData, "blob digest has no prefix")
        })?;
        Ok(self
            .root
            .join(&blob_ref.algorithm)
            .join(prefix)
            .join(format!("{digest}.blob")))
    }

    pub fn write_blob(&self, bytes: &[u8]) -> io::Result<BlobRef> {
        let blob_ref = BlobRef::sha256(bytes);
        let path = self.path_for(&blob_ref)?;
        if path.is_file() {
            return Ok(blob_ref);
        }

        let parent = path.parent().ok_or_else(|| {
            io::Error::new(io::ErrorKind::InvalidInput, "blob path has no parent")
        })?;

View on GitHub (pinned to bd85ce9dee)