{"record":{"id":"245dc972e163f14d","repo":"astrid-runtime/astrid","slug":"unknown-byte-suffix-other","errorCode":null,"errorMessage":"unknown byte suffix: {other}","messagePattern":"unknown byte suffix: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/quota.rs","lineNumber":376,"sourceCode":"\nfn parse_numeric_suffix(body: &str) -> Result<(&str, u64)> {\n    // Find the index where the suffix (alphabetic or `i` for binary)\n    // begins. Consume digits and at most one `.`.\n    let split = body\n        .find(|c: char| !(c.is_ascii_digit() || c == '.'))\n        .unwrap_or(body.len());\n    let (num_part, suffix) = body.split_at(split);\n    let mult = match suffix.trim().to_ascii_uppercase().as_str() {\n        \"\" | \"B\" => 1u64,\n        \"K\" | \"KB\" => 1_000,\n        \"KIB\" => 1024,\n        \"M\" | \"MB\" => 1_000_000,\n        \"MIB\" => 1024 * 1024,\n        \"G\" | \"GB\" => 1_000_000_000,\n        \"GIB\" => 1024 * 1024 * 1024,\n        \"T\" | \"TB\" => 1_000_000_000_000,\n        \"TIB\" => 1024_u64.pow(4),\n        other => anyhow::bail!(\"unknown byte suffix: {other}\"),\n    };\n    Ok((num_part, mult))\n}\n\n/// Parse `\"30s\"`, `\"5m\"`, `\"1h\"`, `\"2h30m\"`, `\"500ms\"`. Falls back to\n/// seconds for a bare integer.\npub(crate) fn parse_duration(s: &str) -> Result<Duration> {\n    let trimmed = s.trim();\n    if trimmed.is_empty() {\n        anyhow::bail!(\"empty duration\");\n    }\n    if let Ok(secs) = trimmed.parse::<u64>() {\n        return Ok(Duration::from_secs(secs));\n    }\n    let mut total = Duration::ZERO;\n    let mut current = String::new();\n    let mut iter = trimmed.chars().peekable();\n    while let Some(c) = iter.next() {","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/quota.rs#L358-L394","documentation":"`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.","triggerScenarios":"`--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.","commonSituations":"Assuming all SI prefixes are supported (PB, EB), writing unusual casing/spacing, or appending stray words after the unit.","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"],"exampleFix":"// before\nastrid quota set --storage 2PB\n// after\nastrid quota set --storage 2000TB","handlingStrategy":"validation","validationCode":"const BYTE_SUFFIXES: [&str; 10] = [\"B\",\"KB\",\"MB\",\"GB\",\"TB\",\"KIB\",\"MIB\",\"GIB\",\"TIB\",\"\"];\nfn valid_bytes(s: &str) -> bool {\n    let body = s.trim().trim_end_matches(\"/s\");\n    let (_, suffix) = body.split_at(body.find(|c: char| !c.is_ascii_digit() && c != '.').unwrap_or(body.len()));\n    BYTE_SUFFIXES.contains(&suffix.to_ascii_uppercase().as_str())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["cli","parsing","units"],"backgroundTag":"invalid-argument-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}