{"record":{"id":"2e89a09b11d4801f","repo":"rustfs/rustfs","slug":"last-modified-time-format-is-invalid","errorCode":null,"errorMessage":"Last-Modified time format is invalid","messagePattern":"Last-Modified time format is invalid","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/ecstore/src/client/transition_api.rs","lineNumber":1265,"sourceCode":"        let content_length_str = get_header(\"Content-Length\");\n        if !content_length_str.is_empty() {\n            content_length_str\n                .parse::<i64>()\n                .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, \"Content-Length is not an integer\"))?\n        } else {\n            -1\n        }\n    };\n\n    // Parse Last-Modified time\n    let mod_time = {\n        let last_modified_str = get_header(\"Last-Modified\");\n        if !last_modified_str.is_empty() {\n            // Parse HTTP date format (RFC 7231)\n            // Using time crate to parse HTTP dates\n            let parsed_time = OffsetDateTime::parse(&last_modified_str, &time::format_description::well_known::Rfc2822)\n                .or_else(|_| OffsetDateTime::parse(&last_modified_str, &time::format_description::well_known::Rfc3339))\n                .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, \"Last-Modified time format is invalid\"))?;\n            Some(parsed_time)\n        } else {\n            Some(OffsetDateTime::now_utc())\n        }\n    };\n\n    // Get content type\n    let content_type = {\n        let content_type_raw = get_header(\"Content-Type\");\n        let content_type_trimmed = content_type_raw.trim();\n        if content_type_trimmed.is_empty() {\n            Some(\"application/octet-stream\".to_string())\n        } else {\n            Some(content_type_trimmed.to_string())\n        }\n    };\n\n    // Parse Expires time","sourceCodeStart":1247,"sourceCodeEnd":1283,"githubUrl":"https://github.com/rustfs/rustfs/blob/9e6e02ea09c86bedf44c7bd64a74ea02a0cff1de/crates/ecstore/src/client/transition_api.rs#L1247-L1283","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match stat_object_from_headers(&headers) {\n    Ok(info) => Ok(info),\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {\n        tracing::error!(event = \"tier_stat_header_invalid\", header = \"Last-Modified\", \"unparseable HTTP-date from tier; failing closed\");\n        Err(e)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["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."],"tags":["rust","s3","remote-tier","http-date","stat"],"backgroundTag":"http-date-parse-failed","analyzedSha":"9e6e02ea09c86bedf44c7bd64a74ea02a0cff1de","analyzedAt":"2026-08-16T20:34:17.560Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}