rustfs/rustfs · error · std::io::Error
InvalidData
InvalidData
Error message
GCS remote version is not a valid generation
What it means
Thrown by parse_generation in the GCS warm backend. GCS identifies object versions with numeric 'generation' values, so any stored remote version must parse as i64. When a non-empty remote version string fails i64::parse (contains letters, dashes, or is an S3-style UUID), the backend reports InvalidData: the metadata does not describe a GCS generation.
Source
Thrown at crates/ecstore/src/services/tier/warm_backend_gcs.rs:52
admin_handler_utils::AdminError,
api_put_object::PutObjectOptions,
transition_api::{Options, ReadCloser, ReaderImpl},
};
use crate::services::tier::{
tier_config::TierGCS,
warm_backend::{WarmBackend, WarmBackendGetOpts},
};
use tracing::warn;
const _MAX_PART_SIZE: i64 = 1024 * 1024 * 1024 * 5;
fn parse_generation(remote_version: &str) -> Result<Option<i64>, Error> {
if remote_version.is_empty() {
return Ok(None);
}
let generation = remote_version
.parse::<i64>()
.map_err(|_| Error::new(ErrorKind::InvalidData, "GCS remote version is not a valid generation"))?;
if generation <= 0 {
return Err(Error::new(ErrorKind::InvalidData, "GCS remote version generation must be positive"));
}
Ok(Some(generation))
}
pub struct WarmBackendGCS {
pub client: Arc<Storage>,
pub control: Arc<StorageControl>,
pub bucket: String,
pub prefix: String,
}
impl WarmBackendGCS {
pub async fn new(conf: &TierGCS, tier: &str) -> Result<Self, std::io::Error> {
if conf.creds == "" {
return Err(std::io::Error::other("both access and secret keys are required"));
}View on GitHub (pinned to 9e6e02ea09)
Solutions
- Verify the tier configuration: a tier name must keep pointing at the same backend/prefix it was created with; re-pointing a tier from S3 to GCS strands old version metadata
- Create a fresh GCS tier (new name or new prefix) and re-transition the affected objects so their metadata stores numeric generations
- Delete the stale transition metadata for objects that were transitioned by the previous backend and let lifecycle re-evaluate them
- Never mix providers under one tier prefix
Example fix
# before: tier TIER1 re-pointed from S3 to GCS, metadata has UUID versions rustfs ilm tier edit gcs TIER1 --bucket gs-bucket --prefix old/ # after: new tier + re-transition rustfs ilm tier add gcs TIER_GCS --bucket gs-bucket --prefix gcs-only/ # then remove/re-transition objects that carry S3 UUID remote versions
Defensive patterns
Strategy: type-guard
Type guard
// Accept only numeric generations before GCS tier operations
fn is_gcs_generation(v: &str) -> bool {
v.is_empty() || v.parse::<i64>().map(|g| g > 0).unwrap_or(false)
} Try / catch
match parse_generation(&remote_version) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
// metadata was written for a different provider: re-transition under a fresh GCS tier
}
other => other?,
} Prevention
- Never re-point an existing tier name to a different backend; create a new tier
- Keep one provider and one prefix per tier
- Validate stored remote versions against the current tier's format after migrations
When it happens
Trigger: A tier operation on the GCS backend reads a stored remote version that is not numeric — e.g. an S3-style version UUID or 'null' — because the object was transitioned by a different tier/provider, the tier config was re-pointed to GCS, or the transition metadata was manually crafted.
Common situations: Re-creating a tier with the same name but a different backend (S3 -> GCS) so old transition metadata with UUID versions is interpreted as GCS generations; sharing a metadata store across tier configs; MinIO-migrated metadata carrying non-numeric version IDs.
Related errors
AI-assisted analysis of rustfs/rustfs@9e6e02ea09 (2026-08-16).
Data as JSON: /api/errors/cf5291699ae55874.
Report an issue: GitHub.