astrid-runtime/astrid · error

corpus label must contain only lowercase ASCII letters, digi

Error message

corpus label must contain only lowercase ASCII letters, digits, and hyphens

What it means

`validate_label` enforces corpus labels be non-empty strings of only lowercase ASCII letters, digits, and hyphens. This keeps labels safe to embed in report filenames and prevents them from smuggling path components.

Source

Thrown at crates/astrid-storage-chunker-evidence/src/corpus.rs:538

        .with_context(|| format!("stat corpus input {}", path.display()))?
        .len();
    let mut reader = HashingReader::new(BufReader::with_capacity(READER_CAPACITY, file));
    std::io::copy(&mut reader, &mut std::io::sink())
        .with_context(|| format!("snapshot corpus input {}", path.display()))?;
    let snapshot = reader.finish();
    if snapshot.logical_bytes != expected_bytes {
        bail!("corpus input changed while its baseline snapshot was captured");
    }
    Ok(snapshot)
}

fn validate_label(label: &str) -> Result<()> {
    if label.is_empty()
        || !label
            .bytes()
            .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-')
    {
        bail!("corpus label must contain only lowercase ASCII letters, digits, and hyphens");
    }
    Ok(())
}

fn validate_relative_git_path(path: &Path) -> Result<()> {
    if path.as_os_str().is_empty()
        || path.is_absolute()
        || path.components().any(|component| {
            matches!(
                component,
                std::path::Component::ParentDir
                    | std::path::Component::RootDir
                    | std::path::Component::Prefix(_)
            )
        })
        || path.to_string_lossy().contains(':')
    {
        bail!("git history path must be a relative in-repository path");

View on GitHub (pinned to affd8760f4)

Solutions

  1. Rename the corpus to a slug: lowercase letters, digits, hyphens only (e.g. `my-corpus-2024`)
  2. Normalize the label before constructing the corpus: `name.to_lowercase().replace([' ', '_'], "-")`
  3. Reject or auto-slugify user input in your CLI wrapper before passing it to the corpus builder

Example fix

// before
let corpus = Corpus::from_files("My_Corpus/2024", kind, inputs)?;
// after
let label: String = "My_Corpus/2024".to_lowercase().replace([' ', '_', '/'], "-");
let corpus = Corpus::from_files(&label, kind, inputs)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_corpus_label(label: &str) -> bool {
    !label.is_empty() && label.bytes().all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'-')
}
assert!(is_valid_corpus_label(&name), "invalid corpus label: {name}");

Type guard

fn sanitize_label(raw: &str) -> String {
    let s: String = raw.to_lowercase().bytes().filter(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || *b == b'-').map(|b| b as char).collect();
    if s.is_empty() { "corpus".into() } else { s }
}

Try / catch

match Corpus::from_files(&name, kind, inputs) {
    Ok(c) => c,
    Err(e) if e.to_string().contains("corpus label must contain") => {
        let fixed = sanitize_label(&name);
        Corpus::from_files(&fixed, kind, inputs)?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Creating a `Corpus` via `from_files`/`from_directory` with a name that is empty, contains uppercase letters, underscores, spaces, slashes, or non-ASCII characters.

Common situations: Deriving corpus names from filenames that contain uppercase/underscores, using absolute paths as labels, user-supplied CLI names, or names built from `to_string_lossy()` of arbitrary paths.

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


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/2235741ec7b17c6b. Report an issue: GitHub.