{"record":{"id":"61a1bcbe6d1d83bd","repo":"tursodatabase/turso","slug":"failed-to-parse-server-pages-selector","errorCode":null,"errorMessage":"Failed to parse server_pages_selector: {}","messagePattern":"Failed to parse server_pages_selector: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"cli/sync_server.rs","lineNumber":541,"sourceCode":"        } else {\n            req.server_revision.parse().unwrap_or(wal_state.max_frame)\n        };\n\n        let client_revision: u64 = if req.client_revision.is_empty() {\n            0\n        } else {\n            req.client_revision.parse().unwrap_or(0)\n        };\n\n        debug!(\n            \"Using server_revision={}, client_revision={}\",\n            server_revision, client_revision\n        );\n\n        let pages_selector: Option<RoaringBitmap> = if !req.server_pages_selector.is_empty() {\n            Some(\n                RoaringBitmap::deserialize_from(&req.server_pages_selector[..])\n                    .map_err(|e| anyhow!(\"Failed to parse server_pages_selector: {}\", e))?,\n            )\n        } else {\n            None\n        };\n\n        let mut seen_pages: HashSet<u32> = HashSet::new();\n        let mut pages_to_send: Vec<(u32, Vec<u8>)> = Vec::new();\n\n        let frame_size = WAL_FRAME_HEADER_SIZE + PAGE_SIZE;\n        let mut frame_buffer = vec![0u8; frame_size];\n\n        debug!(\n            \"pull-updates: scanning WAL frames {}..={} (client_revision={}, server_revision={})\",\n            client_revision + 1,\n            server_revision,\n            client_revision,\n            server_revision\n        );","sourceCodeStart":523,"sourceCodeEnd":559,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/cli/sync_server.rs#L523-L559","documentation":"server_pages_selector (protobuf tag 5, bytes) carries a RoaringBitmap listing the page ids the client still needs; empty bytes mean 'send all pages'. When the field is non-empty but RoaringBitmap::deserialize_from rejects it, the pull request fails with HTTP 500 before any page is read.","triggerScenarios":"Sending a base64-decoded but wrong blob; a bitmap serialized by a different Roaring implementation or serialization variant; truncated bytes; page ids outside the u32 domain of the bitmap.","commonSituations":"Chunked bootstrap code that caches selector blobs between sessions; interop between roaring crate versions; hand-assembled pull requests in tests.","solutions":["Build the selector with the same roaring crate the server uses: collect ids into RoaringBitmap and serialize_into a buffer.","Round-trip check locally (serialize then deserialize_from) before sending the request.","Omit the field (empty bytes) to request all pages when chunking is not needed.","Verify cached selector blobs are byte-identical to what the client's roaring crate emits on its platform."],"exampleFix":"// before\nreq.server_pages_selector = Bytes::from(raw_bitset_bytes);\n\n// after\nuse roaring::RoaringBitmap;\nlet bitmap: RoaringBitmap = missing_pages.into_iter().collect();\nlet mut buf = Vec::new();\nbitmap.serialize_into(&mut buf)?;\nreq.server_pages_selector = Bytes::from(buf);","handlingStrategy":"validation","validationCode":"if !req.server_pages_selector.is_empty() {\n    roaring::RoaringBitmap::deserialize_from(&req.server_pages_selector[..])\n        .map_err(|e| format!(\"selector blob is not a valid RoaringBitmap: {e}\"))?;\n}","typeGuard":null,"tryCatchPattern":"On 500 'Failed to parse server_pages_selector', drop the selector (send empty bytes = all pages) or rebuild the bitmap and retry; never resend the same blob.","preventionTips":["Serialize selectors with the same roaring crate version the server uses.","Round-trip check (serialize then deserialize) cached blobs before reuse.","Omit the selector unless chunked bootstrap is required."],"tags":["roaring-bitmap","sync","pages","serialization"],"backgroundTag":"invalid-bitmap-filter","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}