neondatabase/neon · error
unexpected be message kind in response to getpage request: {
Error message
unexpected be message kind in response to getpage request: {} What it means
`PagestreamReceiver::getpage_recv` matches on the next backend message and expects `GetPage`; receiving Exists, Nblocks, DbSize, GetSlruSegment (or the testing-only Test variant) means the response kind doesn't pair with the getpage request that was sent. The pagestream protocol is strictly request/response, so this indicates the recv method was mismatched to the request or responses were consumed out of order.
Source
Thrown at pageserver/client/src/page_service.rs:241
impl PagestreamReceiver {
// TODO: maybe make this impl Stream instead for better composability?
pub async fn recv(&mut self) -> anyhow::Result<PagestreamBeMessage> {
let next: Option<Result<bytes::Bytes, _>> = self.stream.next().await;
let next: bytes::Bytes = next.unwrap()?;
PagestreamBeMessage::deserialize(next)
}
pub async fn getpage_recv(&mut self) -> anyhow::Result<PagestreamGetPageResponse> {
let next: PagestreamBeMessage = self.recv().await?;
match next {
PagestreamBeMessage::GetPage(p) => Ok(p),
PagestreamBeMessage::Error(e) => anyhow::bail!("Error: {:?}", e),
PagestreamBeMessage::Exists(_)
| PagestreamBeMessage::Nblocks(_)
| PagestreamBeMessage::DbSize(_)
| PagestreamBeMessage::GetSlruSegment(_) => {
anyhow::bail!(
"unexpected be message kind in response to getpage request: {}",
next.kind()
)
}
#[cfg(feature = "testing")]
PagestreamBeMessage::Test(_) => {
anyhow::bail!(
"unexpected be message kind in response to getpage request: {}",
next.kind()
)
}
}
}
}
View on GitHub (pinned to 8f60b04da4)
Solutions
- Pair each request with its matching recv function (e.g. exists request → exists-style recv, nblocks request → nblocks recv)
- Serialize requests on a single pagestream connection: send, recv, then send the next
- Use the message's `kind()` in the error output to see which response actually arrived and infer which request it belongs to
- Add a debug assertion logging request/response kinds during development
Example fix
// before: mismatched request/response pairing pagestream.exists_send(&req).await?; let page = pagestream.getpage_recv().await?; // unexpected be message kind // after: match recv to the request sent pagestream.exists_send(&req).await?; let exists = pagestream.exists_recv().await?;
Defensive patterns
Strategy: validation
Validate before calling
// ensure the response kind matches the request before consuming it
let msg = pagestream.recv().await?;
if msg.kind() != BeaconKind::GetPage {
anyhow::bail!("expected GetPage response, got {} — check send/recv pairing", msg.kind());
} Type guard
fn is_getpage_response(msg: &PagestreamBeMessage) -> bool {
matches!(msg, PagestreamBeMessage::GetPage(_))
} Prevention
- Pair every send helper with its matching recv helper; review during code review
- Serialize pagestream requests: one in flight per receiver at a time
- Log request and response kinds together in debug builds to catch drift early
When it happens
Trigger: Sending a different request kind (exists/nblocks/dbsize/getslrusegment) but calling `getpage_recv` for the reply; or interleaving multiple requests on one receiver so a later response is read as the getpage answer.
Common situations: Copy-pasted client code pairing the wrong send/recv helpers; refactors that changed request order; concurrent access to a single PagestreamReceiver without serialization.
Related errors
- Error: {:?}
- invalid tag {tag}
- Non-overlapping bounds: other.max = {} was less than self.mi
- Non-overlappinng bounds: self.max = {} was less than other.m
- Unsupported key decoded at LSN {}: {}
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/481c091677d0ae74.
Report an issue: GitHub.