can1357/oh-my-pi · error · io::Error

missing

Error message

missing {name}

What it means

parse_i32_part extracts a signed 32-bit date component (e.g. year) from an Option<&str> produced by splitting a date string. When the expected component is absent (None), it throws InvalidInput with 'missing {name}' where name identifies which part (year, etc.) was expected. It also converts any parse failure of the present string into an InvalidInput error.

Solutions

  1. Supply the full date including the year, e.g. '1997-12-25'
  2. Check the expected date format documented for the fd builtin's filter option
  3. Quote the argument in your shell so dashes/hyphens are not misinterpreted

Example fix

// before
fd --newer '12-25' .
// after
fd --newer '1997-12-25' .
Defensive patterns

Strategy: validation

Validate before calling

fn validate_date_has_year(date: &str) -> Result<(), String> {
	let parts: Vec<&str> = date.split('-').collect();
	if parts.len() < 3 {
		return Err(format!("expected YYYY-MM-DD, got '{date}'"));
	}
	Ok(())
}

Try / catch

match builtin_result {
	Err(e) if e.to_string().starts_with("missing ") => eprintln!("date argument incomplete: {e}"),
	Err(e) => return Err(e),
	Ok(v) => /* ... */,
}

Prevention

When it happens

Trigger: Passing a date string to the fd builtin that lacks a required numeric component, e.g. omitting the year in a date filter so the split yields fewer parts than the parser expects, causing parse_i32_part to receive None for that field.

Common situations: Malformed CLI date arguments like '--newer 12-25' (missing year), locale-dependent date formats with omitted fields, empty date strings after trimming.

Related errors


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

Appendix: source

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

		|| minute > 59
		|| second > 59
	{
		return Err(io::Error::new(io::ErrorKind::InvalidInput, format!("invalid date: {value}")));
	}
	let days = days_from_civil(year, month, day);
	let seconds = days
		.checked_mul(86_400)
		.and_then(|base| base.checked_add(i64::from(hour * 3_600 + minute * 60 + second)))
		.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "date is out of range"))?;
	if seconds < 0 {
		return Err(io::Error::new(io::ErrorKind::InvalidInput, "dates before 1970 are unsupported"));
	}
	Ok(UNIX_EPOCH + Duration::from_secs(u64::try_from(seconds).unwrap_or(u64::MAX)))
}

fn parse_i32_part(value: Option<&str>, name: &str) -> io::Result<i32> {
	value
		.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, format!("missing {name}")))?
		.parse::<i32>()
		.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))
}

fn parse_u32_part(value: Option<&str>, name: &str) -> io::Result<u32> {
	value
		.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, format!("missing {name}")))?
		.parse::<u32>()
		.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))
}

fn days_from_civil(year: i32, month: u32, day: u32) -> i64 {
	let year = year - i32::from(month <= 2);
	let era = if year >= 0 { year } else { year - 399 } / 400;
	let year_of_era = year - era * 400;
	let month = i32::try_from(month).unwrap_or(0);
	let day = i32::try_from(day).unwrap_or(0);
	let day_of_year = (153 * (month + if month > 2 { -3 } else { 9 }) + 2) / 5 + day - 1;

View on GitHub (pinned to 9690622007)