rustfs/rustfs · error · std::io::Error

remote tier returned an oversized object version id header

Error message

remote tier returned an oversized object version id header

What it means

validate_remote_version_id caps remote version IDs at MAX_REMOTE_VERSION_ID_LEN (1024 bytes in crates/ecstore/src/client/provider_versions.rs:23); a longer raw version header is rejected as InvalidData. Real S3 version IDs are short base64 strings, so an oversized header signals a broken or hostile endpoint, and accepting it would let unbounded data into object metadata.

Source

Thrown at crates/ecstore/src/client/provider_versions.rs:185

                }
            });
        };
        if value == "null" {
            return Ok(RemoteVersion::SuspendedNull);
        }
        Ok(RemoteVersion::Exact(value.to_string()))
    }
}

pub(crate) fn validate_remote_version_id(version_id: &str) -> Result<(), Error> {
    if version_id.is_empty() {
        return Err(Error::new(
            ErrorKind::InvalidData,
            "remote tier returned an empty object version id header",
        ));
    }
    if version_id.len() > MAX_REMOTE_VERSION_ID_LEN {
        return Err(Error::new(
            ErrorKind::InvalidData,
            "remote tier returned an oversized object version id header",
        ));
    }
    if version_id.chars().any(char::is_control) {
        return Err(Error::new(
            ErrorKind::InvalidData,
            "remote tier returned an object version id containing control characters",
        ));
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::{BucketVersioningState, ConditionalCreateCapability, ProviderVersionCapabilities, RemoteVersion};
    use http::{HeaderMap, HeaderValue};

View on GitHub (pinned to 9e6e02ea09)

Solutions

  1. Inspect the raw headers of the failing response to confirm the header's actual content and length.
  2. Point the tier at a compliant S3 endpoint or remove the misbehaving intermediary.
  3. Only raise the limit if a legitimate provider genuinely emits longer IDs, and do it deliberately with a documented reason - never remove the cap.
Defensive patterns

Strategy: try-catch

Try / catch

match provider_caps.raw_version_id(&headers) {
    Ok(v) => Ok(v),
    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
        tracing::error!(event = "remote_version_header_invalid", result = "rejected", "oversized version-id header from tier");
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: A remote-tier object response carries a version-id header longer than 1024 characters - garbage appended by a malfunctioning gateway, error text placed in the header slot by a non-S3 service, or deliberately malformed responses from an adversarial endpoint.

Common situations: Buggy load balancers appending data to headers; tier endpoints that are not S3 responding with their own error payloads; fuzzing or hostile middleboxes on the path to the tier.

Related errors


AI-assisted analysis of rustfs/rustfs@9e6e02ea09 (2026-08-16). Data as JSON: /api/errors/4361ac7c827a8e59. Report an issue: GitHub.