{"record":{"id":"a6ce7468036928ec","repo":"neondatabase/neon","slug":"invalid-slrukind-clog-record-block-len","errorCode":null,"errorMessage":"invalid SlruKind::Clog record: block.len()={}","messagePattern":"invalid SlruKind::Clog record: block\\.len\\(\\)=(.+?)","errorType":"exception","errorClass":"BasebackupError","httpStatus":null,"severity":"error","filePath":"pageserver/src/basebackup.rs","lineNumber":260,"sourceCode":"where\n    W: AsyncWrite + Send + Sync + Unpin,\n{\n    fn new(ar: &'a mut Builder<&'b mut W>) -> Self {\n        Self {\n            ar,\n            buf: Vec::new(),\n            current_segment: None,\n            total_blocks: 0,\n        }\n    }\n\n    async fn add_block(&mut self, key: &Key, block: Bytes) -> Result<(), BasebackupError> {\n        let (kind, segno, _) = key.to_slru_block()?;\n\n        match kind {\n            SlruKind::Clog => {\n                if !(block.len() == BLCKSZ as usize || block.len() == BLCKSZ as usize + 8) {\n                    return Err(BasebackupError::Server(anyhow!(\n                        \"invalid SlruKind::Clog record: block.len()={}\",\n                        block.len()\n                    )));\n                }\n            }\n            SlruKind::MultiXactMembers | SlruKind::MultiXactOffsets => {\n                if block.len() != BLCKSZ as usize {\n                    return Err(BasebackupError::Server(anyhow!(\n                        \"invalid {:?} record: block.len()={}\",\n                        kind,\n                        block.len()\n                    )));\n                }\n            }\n        }\n\n        let segment = (kind, segno);\n        match self.current_segment {","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/pageserver/src/basebackup.rs#L242-L278","documentation":"During basebackup SLRU assembly, every clog (pg_xact) page image must be exactly BLCKSZ (8192) or BLCKSZ+8 (8200, the long-page-header form). Any other length means the image reconstructed from timeline layers is malformed, so the pageserver aborts the basebackup rather than shipping corrupt data.","triggerScenarios":"A clog block image of unexpected size returned for a key decoded by to_slru_block(): corrupted layer files (local or remote), a page-image reconstruction bug, or pg-version dispatch producing the wrong page layout.","commonSituations":"Bit rot or partial writes in layer storage; corrupted remote-storage objects after transfer failures; old branches written by different neon versions.","solutions":["Check pageserver logs for layer read or reconstruction errors near the failure","Retry the basebackup at a different LSN or after a restart to rule out transient reads","Validate the tenant's layers and their remote copies","If corruption is confirmed, rebuild the tenant from a healthy branch or backup"],"exampleFix":"// before: trust any returned image\nlet img = timeline.get_rel_page(key, Version::at(lsn), ctx).await?;\n// after: validate size at read time to catch corruption early\nif !matches!(img.len(), 8192 | 8200) {\n    tracing::error!(?key, len = img.len(), \"unexpected clog page size\");\n    anyhow::bail!(\"corrupt clog image for {key}\");\n}","handlingStrategy":"validation","validationCode":"// periodic scrub: verify every clog block image size without taking a basebackup\nfor key in scan_slru_keys(SlruKind::Clog).await? {\n    let img = timeline.get(key, lsn, ctx).await?;\n    if !matches!(img.len(), 8192 | 8200) {\n        alert_corruption(ttid, key, img.len());\n    }\n}","typeGuard":"fn is_valid_clog_page(img: &bytes::Bytes) -> bool {\n    matches!(img.len(), 8192 | 8200)\n}","tryCatchPattern":"match serve_basebackup(request).await {\n    Ok(b) => b,\n    Err(e) if e.to_string().contains(\"invalid SlruKind::Clog record\") => {\n        // schedule layer validation; surface a corruption alert, do not retry\n        corruption_alert(ttid, e).await;\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Run periodic tenant and layer validation jobs","Monitor basebackup failures per tenant for corruption signatures","Verify remote-storage object checksums after large uploads","Keep neon versions consistent when writing long-lived branches"],"tags":["pageserver","basebackup","slru","clog","data-integrity","page-validation"],"backgroundTag":"corrupt-page-image","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}