nikivdev/code · error

archive message must include at least one letter or number

Error message

archive message must include at least one letter or number

What it means

Thrown by archive.rs run when the message is non-empty but sanitize_segment(message) yields an empty slug — i.e. the message contains no letters or numbers (only punctuation/symbols). The slug is used to name the archive directory, so it must be alphanumeric at least in part.

Source

Thrown at src/archive.rs:26

use crate::cli::ArchiveOpts;

pub fn run(opts: ArchiveOpts) -> Result<()> {
    let root =
        ai_context::find_project_root().ok_or_else(|| anyhow::anyhow!("project root not found"))?;
    let root = fs::canonicalize(&root).unwrap_or(root);
    let project_name = root
        .file_name()
        .and_then(|name| name.to_str())
        .filter(|name| !name.trim().is_empty())
        .unwrap_or("project");

    let message = opts.message.trim();
    if message.is_empty() {
        bail!("archive message cannot be empty");
    }
    let slug = sanitize_segment(message);
    if slug.is_empty() {
        bail!("archive message must include at least one letter or number");
    }

    let home = dirs::home_dir()
        .ok_or_else(|| anyhow::anyhow!("could not resolve home directory"))?
        .to_path_buf();
    let archive_root = home.join("archive").join("code");
    fs::create_dir_all(&archive_root).with_context(|| {
        format!(
            "failed to create archive directory {}",
            archive_root.display()
        )
    })?;

    let code_root = fs::canonicalize(home.join("code")).unwrap_or_else(|_| home.join("code"));
    let rel_path = root.strip_prefix(&code_root).ok();
    let (dest_parent, base_project) = if let Some(rel) = rel_path {
        let parent = rel
            .parent()

View on GitHub (pinned to a747e741ae)

Solutions

  1. Include at least one letter or digit in the message, e.g. `--message "v1-release"`
  2. Check interpolated template values actually render non-symbolic content
  3. Review sanitize_segment to see which characters are retained before choosing a message

Example fix

// before
archive --message "!!!"
// after
archive --message "release-1"
Defensive patterns

Strategy: validation

Validate before calling

fn slug_ok(msg: &str) -> bool {
    msg.chars().any(|c| c.is_alphanumeric())
}
if !slug_ok(opts.message.trim()) {
    return Err("message needs at least one letter or digit".into());
}

Try / catch

match archive::run(opts) {
    Err(e) if e.to_string().contains("at least one letter or number") => {
        eprintln!("Message must contain alphanumeric characters.");
        std::process::exit(2);
    }
    other => other,
}

Prevention

When it happens

Trigger: Messages like `--message "!!!"` or `--message "---"` that survive the empty check but strip to nothing under sanitize_segment.

Common situations: Punctuation-only placeholder messages; templates where the meaningful text was interpolated away; shell quoting mistakes leaving only symbols.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/8080b38606afaa40. Report an issue: GitHub.