astrid-runtime/astrid · error

unknown byte suffix: {other}

Error message

unknown byte suffix: {other}

What it means

`parse_numeric_suffix`, called from `parse_bytes`, matches the unit suffix of a byte specifier against a fixed table (B, KB, MIB, GB, TB, TIB, etc., case-insensitive). Any other suffix is rejected with the offending text included.

Source

Thrown at crates/astrid-cli/src/commands/quota.rs:376

fn parse_numeric_suffix(body: &str) -> Result<(&str, u64)> {
    // Find the index where the suffix (alphabetic or `i` for binary)
    // begins. Consume digits and at most one `.`.
    let split = body
        .find(|c: char| !(c.is_ascii_digit() || c == '.'))
        .unwrap_or(body.len());
    let (num_part, suffix) = body.split_at(split);
    let mult = match suffix.trim().to_ascii_uppercase().as_str() {
        "" | "B" => 1u64,
        "K" | "KB" => 1_000,
        "KIB" => 1024,
        "M" | "MB" => 1_000_000,
        "MIB" => 1024 * 1024,
        "G" | "GB" => 1_000_000_000,
        "GIB" => 1024 * 1024 * 1024,
        "T" | "TB" => 1_000_000_000_000,
        "TIB" => 1024_u64.pow(4),
        other => anyhow::bail!("unknown byte suffix: {other}"),
    };
    Ok((num_part, mult))
}

/// Parse `"30s"`, `"5m"`, `"1h"`, `"2h30m"`, `"500ms"`. Falls back to
/// seconds for a bare integer.
pub(crate) fn parse_duration(s: &str) -> Result<Duration> {
    let trimmed = s.trim();
    if trimmed.is_empty() {
        anyhow::bail!("empty duration");
    }
    if let Ok(secs) = trimmed.parse::<u64>() {
        return Ok(Duration::from_secs(secs));
    }
    let mut total = Duration::ZERO;
    let mut current = String::new();
    let mut iter = trimmed.chars().peekable();
    while let Some(c) = iter.next() {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Use a supported unit: B, KB, MB, GB, TB, KiB, MiB, GiB, TiB (lowercase OK)
  2. Check the doc comment on parse_bytes for the full accepted list
  3. Pre-convert exotic units (e.g. 2PB -> 2000TB) before passing them

Example fix

// before
astrid quota set --storage 2PB
// after
astrid quota set --storage 2000TB
Defensive patterns

Strategy: validation

Validate before calling

const BYTE_SUFFIXES: [&str; 10] = ["B","KB","MB","GB","TB","KIB","MIB","GIB","TIB",""];
fn valid_bytes(s: &str) -> bool {
    let body = s.trim().trim_end_matches("/s");
    let (_, suffix) = body.split_at(body.find(|c: char| !c.is_ascii_digit() && c != '.').unwrap_or(body.len()));
    BYTE_SUFFIXES.contains(&suffix.to_ascii_uppercase().as_str())
}

Prevention

When it happens

Trigger: `--storage 10PB`, `--storage 5kib` typo variants not in the table, `--storage 10 bytes`, or a value like `10 kB/s` where only `/s` is stripped and `K` variants are unsupported.

Common situations: Assuming all SI prefixes are supported (PB, EB), writing unusual casing/spacing, or appending stray words after the unit.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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