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
- Use a supported unit: B, KB, MB, GB, TB, KiB, MiB, GiB, TiB (lowercase OK)
- Check the doc comment on parse_bytes for the full accepted list
- 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
- Restrict user-facing inputs to a dropdown/enum of supported units
- Convert exotic units (PB/EB) to supported ones upstream
- Check the parser's doc comment for the accepted suffix list before scripting
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
- empty byte specifier
- byte value must be non-negative and finite
- empty duration
- unknown duration suffix: {other}
- --var must be KEY=VALUE (got {item:?})
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/245dc972e163f14d.
Report an issue: GitHub.