can1357/oh-my-pi · error

err.to_string() (timestamp parse error)

Error message

err.to_string() (timestamp parse error)

What it means

This is an `io::Error` with `ErrorKind::InvalidInput` produced by the fd builtin's time-filter parser (`parse_time_filter`). When a time-filter value is given in `@SECONDS` form (seconds since the Unix epoch), the numeric portion must parse as a `u64`; if it doesn't, the library wraps the standard `ParseIntError` message via `err.to_string()` and surfaces it as InvalidInput. The error means the caller supplied a non-numeric (or out-of-u64-range) timestamp after the `@` prefix.

Source

Thrown at crates/pi-builtins/src/fd.rs:1340

		"ti" => 1_099_511_627_776,
		_ => {
			return Err(io::Error::new(
				io::ErrorKind::InvalidInput,
				format!("invalid size unit: {unit}"),
			));
		},
	};
	let bytes = count.checked_mul(multiplier).ok_or_else(|| {
		io::Error::new(io::ErrorKind::InvalidInput, format!("size is too large: {value}"))
	})?;
	Ok(SizeFilter { ordering, bytes })
}

fn parse_time_filter(value: &str) -> io::Result<SystemTime> {
	if let Some(timestamp) = value.strip_prefix('@') {
		let seconds = timestamp
			.parse::<u64>()
			.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))?;
		return Ok(UNIX_EPOCH + Duration::from_secs(seconds));
	}
	if let Some(duration) = parse_duration(value)? {
		return SystemTime::now().checked_sub(duration).ok_or_else(|| {
			io::Error::new(io::ErrorKind::InvalidInput, format!("duration is too large: {value}"))
		});
	}
	parse_utc_datetime(value)
}

fn parse_duration(value: &str) -> io::Result<Option<Duration>> {
	let trimmed = value.trim();
	let split = trimmed
		.char_indices()
		.find(|(_, ch)| !ch.is_ascii_digit())
		.map_or(trimmed.len(), |(index, _)| index);
	if split == 0 || split == trimmed.len() {
		return Ok(None);

View on GitHub (pinned to 9690622007)

Solutions

  1. Convert the timestamp to whole-number seconds since the Unix epoch, e.g. `date -d '2024-01-01' +%s`, and pass `@<seconds>`.
  2. Remove any fractional/negative part: the parser only accepts non-negative integer seconds, so drop milliseconds or use a duration form like `2d` instead.
  3. If you want a relative time, drop the `@` and use a duration value such as `1h`, `3d`, or `2weeks` (accepted units: s/sec(s), m/min(s), h/hr(s), d/day(s), w/week(s)).
  4. If you want an absolute calendar date, drop the `@` and use `YYYY-MM-DD[ HH:MM:SS]` (UTC), which goes through `parse_utc_datetime` instead.

Example fix

// before (invalid: fractional epoch)
find --changed @1704067200.5
// after (valid: integer epoch seconds, or duration)
find --changed @1704067200
find --changed 2d
Defensive patterns

Strategy: validation

Validate before calling

fn validate_epoch_filter(value: &str) -> Result<(), String> {
    match value.strip_prefix('@') {
        Some(ts) if !ts.is_empty() && ts.bytes().all(|b| b.is_ascii_digit()) => {
            match ts.parse::<u64>() {
                Ok(_) => Ok(()),
                Err(e) => Err(format!("epoch seconds invalid: {e}")),
            }
        }
        _ => Ok(()), // not an @-timestamp; other parse paths apply
    }
}

Type guard

fn is_epoch_filter(value: &str) -> bool {
    match value.strip_prefix('@') {
        Some(ts) => !ts.is_empty() && ts.parse::<u64>().is_ok(),
        None => false,
    }
}

Try / catch

match parse_time_filter(input) {
    Ok(time) => use_time(time),
    Err(e) if e.kind() == io::ErrorKind::InvalidInput => {
        eprintln!("bad time filter '{input}': {e}; expected @<epoch-seconds>, <duration>, or YYYY-MM-DD [HH:MM:SS]");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Passing a time filter value starting with `@` whose remainder is not a valid unsigned integer, e.g. `@abc`, `@12.5`, `@-100`, `@` with nothing after it, or `@99999999999999999999` (overflows u64).

Common situations: Copy-pasting an ISO date into an `@`-style argument instead of an epoch value; using a negative or fractional epoch from another language (JS Date.getTime() milliseconds); forgetting the timestamp entirely and leaving a bare `@`; shell quoting dropping characters so the number is malformed.

Understand the failure class

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/89c3da56c20c1c77. Report an issue: GitHub.