rustfs/rustfs · error · std::io::Error
Last-Modified time format is invalid
Error message
Last-Modified time format is invalid
What it means
While statting a remote-tier object, the Last-Modified header could not be parsed as either an RFC 2822 HTTP-date or an RFC 3339 timestamp, so the whole stat conversion fails with InvalidData. S3 always returns Last-Modified in RFC 2822 form (e.g., 'Sun, 16 Aug 2026 12:00:00 GMT'); anything else marks a non-compliant responder.
Source
Thrown at crates/ecstore/src/client/transition_api.rs:1265
let content_length_str = get_header("Content-Length");
if !content_length_str.is_empty() {
content_length_str
.parse::<i64>()
.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Content-Length is not an integer"))?
} else {
-1
}
};
// Parse Last-Modified time
let mod_time = {
let last_modified_str = get_header("Last-Modified");
if !last_modified_str.is_empty() {
// Parse HTTP date format (RFC 7231)
// Using time crate to parse HTTP dates
let parsed_time = OffsetDateTime::parse(&last_modified_str, &time::format_description::well_known::Rfc2822)
.or_else(|_| OffsetDateTime::parse(&last_modified_str, &time::format_description::well_known::Rfc3339))
.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Last-Modified time format is invalid"))?;
Some(parsed_time)
} else {
Some(OffsetDateTime::now_utc())
}
};
// Get content type
let content_type = {
let content_type_raw = get_header("Content-Type");
let content_type_trimmed = content_type_raw.trim();
if content_type_trimmed.is_empty() {
Some("application/octet-stream".to_string())
} else {
Some(content_type_trimmed.to_string())
}
};
// Parse Expires timeView on GitHub (pinned to 9e6e02ea09)
Solutions
- Inspect the raw Last-Modified value returned by the endpoint with curl -I.
- Fix the endpoint or proxy to emit a proper RFC 2822 HTTP-date.
- For emulators you control, format dates with a standard HTTP-date formatter instead of locale-dependent to_string output.
Defensive patterns
Strategy: try-catch
Try / catch
match stat_object_from_headers(&headers) {
Ok(info) => Ok(info),
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
tracing::error!(event = "tier_stat_header_invalid", header = "Last-Modified", "unparseable HTTP-date from tier; failing closed");
Err(e)
}
Err(e) => Err(e),
} Prevention
- Point tiers at endpoints that emit RFC 2822 HTTP-dates.
- Disable proxy/CDN date rewriting for tier traffic.
- Make CI emulators format dates with a standard HTTP-date formatter.
When it happens
Trigger: Object stat on a tier endpoint or proxy that emits a nonstandard Last-Modified - epoch seconds, locale-formatted dates, or a header overwritten by an intermediary.
Common situations: CDNs/reverse proxies rewriting dates in transit; homegrown S3 emulators in CI using ISO strings with offsets or locale formats; gateways normalizing dates to their own format.
Related errors
- Content-Length is not an integer
- 'Expires' is not in supported format
- x-amz-tagging-count is not an integer
- unexpected GetBucketVersioning XML namespace
- remote object version id is not valid ASCII
AI-assisted analysis of rustfs/rustfs@9e6e02ea09 (2026-08-16).
Data as JSON: /api/errors/2e89a09b11d4801f.
Report an issue: GitHub.