tursodatabase/turso · error
Failed to parse server_pages_selector: {}
Error message
Failed to parse server_pages_selector: {} What it means
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.
Source
Thrown at cli/sync_server.rs:541
} else {
req.server_revision.parse().unwrap_or(wal_state.max_frame)
};
let client_revision: u64 = if req.client_revision.is_empty() {
0
} else {
req.client_revision.parse().unwrap_or(0)
};
debug!(
"Using server_revision={}, client_revision={}",
server_revision, client_revision
);
let pages_selector: Option<RoaringBitmap> = if !req.server_pages_selector.is_empty() {
Some(
RoaringBitmap::deserialize_from(&req.server_pages_selector[..])
.map_err(|e| anyhow!("Failed to parse server_pages_selector: {}", e))?,
)
} else {
None
};
let mut seen_pages: HashSet<u32> = HashSet::new();
let mut pages_to_send: Vec<(u32, Vec<u8>)> = Vec::new();
let frame_size = WAL_FRAME_HEADER_SIZE + PAGE_SIZE;
let mut frame_buffer = vec![0u8; frame_size];
debug!(
"pull-updates: scanning WAL frames {}..={} (client_revision={}, server_revision={})",
client_revision + 1,
server_revision,
client_revision,
server_revision
);View on GitHub (pinned to bad083fafb)
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.
Example fix
// before req.server_pages_selector = Bytes::from(raw_bitset_bytes); // after use roaring::RoaringBitmap; let bitmap: RoaringBitmap = missing_pages.into_iter().collect(); let mut buf = Vec::new(); bitmap.serialize_into(&mut buf)?; req.server_pages_selector = Bytes::from(buf);
Defensive patterns
Strategy: validation
Validate before calling
if !req.server_pages_selector.is_empty() {
roaring::RoaringBitmap::deserialize_from(&req.server_pages_selector[..])
.map_err(|e| format!("selector blob is not a valid RoaringBitmap: {e}"))?;
} Try / catch
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.
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Chunked bootstrap code that caches selector blobs between sessions; interop between roaring crate versions; hand-assembled pull requests in tests.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to decode PullUpdatesRequest: {}
- database page number does not fit u32: {page_no}
- database page {} is missing from replace-base snapshot
- No active remote transaction
- reader is null
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/61a1bcbe6d1d83bd.
Report an issue: GitHub.