neondatabase/neon · error · BasebackupError
img.len() != SIZE_OF_RELMAPFILE, img.len()={}
Error message
img.len() != SIZE_OF_RELMAPFILE, img.len()={} What it means
When a basebackup includes a database's relmapper file (pg_filenode.map), the image fetched via get_relmap_file must equal SIZEOF_RELMAPFILE for the timeline's pg version, selected through dispatch_pgversion!. A different length aborts the basebackup, because shipping a wrong-sized relmap would corrupt the compute's catalog mapping.
Source
Thrown at pageserver/src/basebackup.rs:648
// Each directory contains a PG_VERSION file, and the default database
// directories also contain pg_filenode.map files.
//
async fn add_dbdir(
&mut self,
spcnode: u32,
dbnode: u32,
has_relmap_file: bool,
) -> Result<(), BasebackupError> {
let relmap_img = if has_relmap_file {
let img = self
.timeline
.get_relmap_file(spcnode, dbnode, Version::at(self.lsn), self.ctx)
.await?;
if img.len()
!= dispatch_pgversion!(self.timeline.pg_version, pgv::bindings::SIZEOF_RELMAPFILE)
{
return Err(BasebackupError::Server(anyhow!(
"img.len() != SIZE_OF_RELMAPFILE, img.len()={}",
img.len(),
)));
}
Some(img)
} else {
None
};
if spcnode == GLOBALTABLESPACE_OID {
let pg_version_str = self.timeline.pg_version.versionfile_string();
let header = new_tar_header("PG_VERSION", pg_version_str.len() as u64)?;
self.ar
.append(&header, pg_version_str.as_bytes())
.await
.map_err(|e| BasebackupError::Client(e, "add_dbdir,PG_VERSION"))?;
View on GitHub (pinned to 8f60b04da4)
Solutions
- Verify the tenant's recorded pg_version matches the data it actually contains
- Retry the basebackup, then inspect the relmap keys in the implicated layers
- Validate layer integrity for the tenant
- Recover from a healthy copy if corruption is confirmed
Example fix
// before: length checked only at backup time
// after: check immediately after retrieval with pg-version context
let expected = dispatch_pgversion!(timeline.pg_version, pgv::bindings::SIZEOF_RELMAPFILE);
if img.len() != expected {
tracing::error!(len = img.len(), expected, "relmap size mismatch");
anyhow::bail!("relmap image for db {dbnode} has wrong size");
} Defensive patterns
Strategy: validation
Validate before calling
let expected = dispatch_pgversion!(timeline.pg_version, pgv::bindings::SIZEOF_RELMAPFILE);
anyhow::ensure!(
img.len() == expected,
"relmap len {} != expected {expected} for pg {}",
img.len(),
timeline.pg_version
); Type guard
fn is_valid_relmap(img: &bytes::Bytes, pg_version: u32) -> bool {
img.len() == dispatch_pgversion!(pg_version, pgv::bindings::SIZEOF_RELMAPFILE)
} Try / catch
Err(e) if e.to_string().contains("SIZE_OF_RELMAPFILE") => {
// suspect pg_version mismatch or layer corruption; validate tenant metadata
} Prevention
- Keep tenant pg_version metadata authoritative and validated after upgrades
- Include relmap size checks in periodic tenant scrubbing
- Treat any relmap abort as potential corruption, not a transient error
When it happens
Trigger: The stored relmap image has an unexpected size: truncated or corrupt layer data, or timeline.pg_version recorded with the wrong major so the dispatch picks the wrong SIZEOF_RELMAPFILE constant.
Common situations: Tenants whose recorded pg_version disagrees with the actual data (manual upgrades, restores); damaged remote-storage objects; relmap key handling bugs.
Related errors
- invalid SlruKind::Clog record: block.len()={}
- invalid {:?} record: block.len()={}
- backup_prev {backup_prev} != provided_prev_lsn {provided_pre
- pageserver connection information should be provided
- shard {shard_index} missing from pageserver_connection_info
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/574f4dd818fa2263.
Report an issue: GitHub.