neondatabase/neon · error · BasebackupError
backup_prev {backup_prev} != provided_prev_lsn {provided_pre
Error message
backup_prev {backup_prev} != provided_prev_lsn {provided_prev_lsn} What it means
While serving a basebackup, the pageserver derives prev_lsn from the timeline state: Lsn(0) when the backup targets a client-specified LSN, or the last record's prev for an end-of-timeline backup. If the request also carries prev_lsn, it must equal the derived non-zero value; otherwise the request is rejected because client and server disagree about the WAL position the backup is anchored to.
Source
Thrown at pageserver/src/basebackup.rs:151
// provide prev_lsn. (get_last_record_rlsn() might return it as
// zero, though, if no WAL has been generated on this timeline
// yet.)
let end_of_timeline = timeline.get_last_record_rlsn();
if req_lsn == end_of_timeline.last {
(end_of_timeline.prev, req_lsn)
} else {
(Lsn(0), req_lsn)
}
} else {
// Backup was requested at end of the timeline.
let end_of_timeline = timeline.get_last_record_rlsn();
(end_of_timeline.prev, end_of_timeline.last)
};
// Consolidate the derived and the provided prev_lsn values
let prev_record_lsn = if let Some(provided_prev_lsn) = prev_lsn {
if backup_prev != Lsn(0) && backup_prev != provided_prev_lsn {
return Err(BasebackupError::Server(anyhow!(
"backup_prev {backup_prev} != provided_prev_lsn {provided_prev_lsn}"
)));
}
provided_prev_lsn
} else {
backup_prev
};
info!(
"taking basebackup lsn={lsn}, prev_lsn={prev_record_lsn} \
(full_backup={full_backup}, replica={replica}, gzip={gzip_level:?})",
);
let span = info_span!("send_tarball", backup_lsn=%lsn);
let io_concurrency = IoConcurrency::spawn_from_conf(
timeline.conf.get_vectored_concurrent_io,
timeline
.gateView on GitHub (pinned to 8f60b04da4)
Solutions
- Retry the basebackup so the client resynchronizes with current timeline state, or omit prev_lsn so the server-derived value is used
- Verify compute and pageserver run matching neon versions
- Confirm exactly one pageserver is attached and active for the timeline
- If it persists, capture both LSN values from the message and report it; it usually indicates an LSN bookkeeping bug
Example fix
// before: client always echoes its cached prev_lsn
let req = BasebackupRequest { lsn, prev_lsn: Some(cached_prev), .. };
// after: on 'backup_prev != provided_prev_lsn', retry letting the server derive it
match send_basebackup(lsn, Some(cached_prev)).await {
Err(e) if e.to_string().contains("backup_prev") => {
send_basebackup(lsn, None).await?
}
r => r?,
} Defensive patterns
Strategy: retry
Validate before calling
// before requesting, reconcile the client's last-record view with the server
let server_info = timeline_info_from_mgmt_api().await?;
if client_prev != server_info.last_record_lsn.prev {
// refresh client state instead of sending a stale prev_lsn
} Try / catch
match pageserver_basebackup(req).await {
Ok(stream) => stream,
Err(e) if e.to_string().contains("backup_prev") => {
// prev_lsn disagreement: resync and retry without prev_lsn
pageserver_basebackup(req.with_prev_lsn(None)).await?
}
Err(e) => return Err(e),
} Prevention
- Keep compute and pageserver versions aligned
- Fetch fresh timeline state before requesting end-of-timeline backups
- Alert on repeated prev_lsn mismatches; they indicate state divergence
- Never attach the same timeline to two active pageservers
When it happens
Trigger: End-of-timeline basebackups where the compute's idea of the last record differs from the pageserver's: after failover or re-attach, timeline migration to another pageserver, LSN regression after restoration, or WAL ingestion racing the request; also version skew in how prev_lsn is computed.
Common situations: A compute reconnecting to a recovered pageserver; a timeline attached to two pageservers (split brain); old compute images paired with new pageservers.
Related errors
- invalid SlruKind::Clog record: block.len()={}
- invalid {:?} record: block.len()={}
- img.len() != SIZE_OF_RELMAPFILE, img.len()={}
- 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/4b871b24df2310cb.
Report an issue: GitHub.