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

  1. 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
  2. Create a fresh GCS tier (new name or new prefix) and re-transition the affected objects so their metadata stores numeric generations
  3. Delete the stale transition metadata for objects that were transitioned by the previous backend and let lifecycle re-evaluate them
  4. 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

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.