influxdata/influxdb · warning · YearMonthError
invalid year-month format
Error message
invalid year-month format: {0}, expected YYYY-MM What it means
YearMonthError::InvalidFormat is returned when parsing a year-month string that does not match the expected YYYY-MM format. The offending input is included in the message. YearMonth parsing is strict so retention/window keys remain unambiguous and sortable.
Solutions
- Format the input as exactly YYYY-MM (zero-padded two-digit month) before parsing
- Parse with an explicit format first (e.g. chrono "%Y-%m") and construct YearMonth from the parsed parts
- Trim/normalize user input and reject clearly formatted values with a friendly message upstream
- Check for locale-specific date formatting leaking into the config value
Example fix
// before let ym: YearMonth = "2026/1".parse()?; // InvalidFormat // after let ym: YearMonth = "2026-01".parse()?;
Defensive patterns
Strategy: validation
Validate before calling
fn valid_ym_str(s: &str) -> bool {
let b = s.as_bytes();
b.len() == 7 && b[4] == b'-' && s[..4].bytes().all(|c| c.is_ascii_digit())
&& s[5..].bytes().all(|c| c.is_ascii_digit())
} Type guard
fn looks_like_yyyy_mm(s: &str) -> bool {
s.len() == 7 && s.as_bytes()[4] == b'-' && s.split('-').count() == 2
} Try / catch
match s.parse::<YearMonth>() {
Err(YearMonthError::InvalidFormat(raw)) => {
eprintln!("{:?} is not YYYY-MM; normalizing...", raw);
chrono::NaiveDate::parse_from_str(&raw, "%Y/%m")
.map(|d| YearMonth::new(d.year(), d.month() as u8).unwrap())?
}
r => r?,
} Prevention
- Normalize all date inputs with chrono ("%Y-%m") before parsing into YearMonth
- Zero-pad months in generated configs and scripts
- Validate retention settings when loading config, not at use time
- Document the YYYY-MM requirement next to the config field
When it happens
Trigger: Calling the YearMonth FromStr/parse implementation with strings like "2026/01", "26-1", "2026-1", empty strings, or values with extra whitespace/characters.
Common situations: Users writing retention configs with slash-separated dates or missing zero padding; API clients sending locale-formatted months; scripts generating dates with inconsistent formatting.
Related errors
- All `DataPoints` must have at least one field. Builder…
- call site contains null bytes
- Custom partition template must have at least one part
- Custom partition template specified
- database name ' ' contains invalid character, character…
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/4ad876c7f1cd5ab0.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_write/src/lib.rs:429
}
/// A year-month value in YYYY-MM format (e.g., "2025-01").
///
/// Used for organizing snapshot checkpoints by month. Stores year and month
/// as integers for efficient comparison and sorting, while serializing to
/// the standard "YYYY-MM" string format for backward compatibility.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct YearMonth {
year: u16,
month: u8,
}
/// Error type for invalid YearMonth values.
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum YearMonthError {
#[error("invalid month {0}, expected 1-12")]
InvalidMonth(u8),
#[error("invalid year-month format: {0}, expected YYYY-MM")]
InvalidFormat(String),
}
impl YearMonth {
/// Create a YearMonth from year and month without validation.
///
/// # Safety
/// Use only when the values are known to be valid (e.g., from chrono).
/// In debug builds, panics if month is not in 1-12.
pub fn new_unchecked(year: u16, month: u8) -> Self {
debug_assert!((1..=12).contains(&month), "month must be 1-12");
Self { year, month }
}
/// Get the year component.
pub fn year(&self) -> u16 {
self.year
}View on GitHub (pinned to 06200ef96b)