{"record":{"id":"511fea05623d2113","repo":"can1357/oh-my-pi","slug":"duration-is-too-large-value","errorCode":null,"errorMessage":"duration is too large: {value}","messagePattern":"duration is too large: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/pi-builtins/src/fd.rs","lineNumber":1345,"sourceCode":"\t\t\t));\n\t\t},\n\t};\n\tlet bytes = count.checked_mul(multiplier).ok_or_else(|| {\n\t\tio::Error::new(io::ErrorKind::InvalidInput, format!(\"size is too large: {value}\"))\n\t})?;\n\tOk(SizeFilter { ordering, bytes })\n}\n\nfn parse_time_filter(value: &str) -> io::Result<SystemTime> {\n\tif let Some(timestamp) = value.strip_prefix('@') {\n\t\tlet seconds = timestamp\n\t\t\t.parse::<u64>()\n\t\t\t.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))?;\n\t\treturn Ok(UNIX_EPOCH + Duration::from_secs(seconds));\n\t}\n\tif let Some(duration) = parse_duration(value)? {\n\t\treturn SystemTime::now().checked_sub(duration).ok_or_else(|| {\n\t\t\tio::Error::new(io::ErrorKind::InvalidInput, format!(\"duration is too large: {value}\"))\n\t\t});\n\t}\n\tparse_utc_datetime(value)\n}\n\nfn parse_duration(value: &str) -> io::Result<Option<Duration>> {\n\tlet trimmed = value.trim();\n\tlet split = trimmed\n\t\t.char_indices()\n\t\t.find(|(_, ch)| !ch.is_ascii_digit())\n\t\t.map_or(trimmed.len(), |(index, _)| index);\n\tif split == 0 || split == trimmed.len() {\n\t\treturn Ok(None);\n\t}\n\tlet count = trimmed[..split]\n\t\t.parse::<u64>()\n\t\t.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))?;\n\tlet unit = trimmed[split..].to_ascii_lowercase();","sourceCodeStart":1327,"sourceCodeEnd":1363,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-builtins/src/fd.rs#L1327-L1363","documentation":"Raised in `parse_time_filter` when a duration-style filter value (e.g. `7d`) parses to a `Duration` that cannot be subtracted from `SystemTime::now()` — `checked_sub` returns None because the result would predate the clock's representable minimum (year 0 on most platforms). The library reports `duration is too large: {value}` as `InvalidInput`, meaning the requested look-back window is absurdly long, not that the duration syntax was wrong.","triggerScenarios":"A duration filter value with a unit parsed by `parse_duration` whose total seconds exceed the platform's SystemTime range backwards from now — practically this needs an enormous count like `99999999999999999d`; note the multiplication saturates per unit, so the huge total only fails at `checked_sub`.","commonSituations":"Fat-fingered extra digits in a duration (`3000000000000000d` instead of `30d`); constructing the duration programmatically by concatenating a variable that already contains seconds with a `d` suffix; misconfigured defaults in scripts that build filter strings dynamically.","solutions":["Check the duration value for extra digits or a wrongly concatenated number and correct it to a sane window (seconds/minutes/hours/days/weeks).","Use a smaller unit so the total stays within a realistic range, e.g. `30d` rather than a centuries-long span.","For a fixed historical cutoff, use an absolute form instead: `@<epoch-seconds>` or `YYYY-MM-DD[ HH:MM:SS]` (UTC), which bypasses the now-minus-duration arithmetic entirely."],"exampleFix":"// before (absurd look-back)\nfind --changed 99999999999999w\n// after\nfind --changed 30d\nfind --changed @1609459200","handlingStrategy":"validation","validationCode":"fn validate_duration_filter(value: &str) -> Result<(), String> {\n    let trimmed = value.trim();\n    let split = trimmed\n        .find(|c: char| !c.is_ascii_digit())\n        .unwrap_or(trimmed.len());\n    if split == 0 || split == trimmed.len() {\n        return Ok(()); // not a duration; other parse paths apply\n    }\n    let count: u64 = trimmed[..split]\n        .parse()\n        .map_err(|e| format!(\"bad duration count: {e}\"))?;\n    let unit = trimmed[split..].to_ascii_lowercase();\n    let secs = match unit.as_str() {\n        \"s\" | \"sec\" | \"secs\" | \"second\" | \"seconds\" => count,\n        \"m\" | \"min\" | \"mins\" | \"minute\" | \"minutes\" => count.saturating_mul(60),\n        \"h\" | \"hr\" | \"hrs\" | \"hour\" | \"hours\" => count.saturating_mul(3600),\n        \"d\" | \"day\" | \"days\" => count.saturating_mul(86_400),\n        \"w\" | \"week\" | \"weeks\" => count.saturating_mul(604_800),\n        _ => return Ok(()),\n    };\n    // A sane look-back bound; anything near i64/SystemTime limits will fail checked_sub.\n    if secs > 100 * 365 * 86_400 {\n        return Err(format!(\"duration too large: {value}\"));\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match parse_time_filter(input) {\n    Ok(time) => use_time(time),\n    Err(e) if e.to_string().starts_with(\"duration is too large\") => {\n        eprintln!(\"look-back window '{input}' exceeds representable time range; use a smaller duration or an absolute date\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Bound durations in code that builds filter strings dynamically (clamp to e.g. max 100 years).","Watch for variable concatenation bugs that append 'd' to an already-large number.","Use absolute dates (`@epoch` or `YYYY-MM-DD`) for anything beyond a few years back.","Sanity-check digit counts in user-supplied durations before passing them through."],"tags":["input-validation","duration","rust","invalid-input"],"backgroundTag":"duration-too-large","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}