neondatabase/neon · error
unexpected status code: {}
Error message
unexpected status code: {} What it means
In the getpage_latest_lsn benchmark every GetPage reply must carry GetPageStatusCode::Ok, meaning a full page image. This ensure! fires when the pageserver answers with any other status (NotModified, BadRequest, InternalError, and so on), so the request/response pairing breaks and the bench aborts the worker.
Source
Thrown at pageserver/pagebench/src/cmd/getpage_latest_lsn.rs:691
blks: Vec<u32>,
) -> anyhow::Result<()> {
let req = page_api::GetPageRequest {
request_id: req_id.into(),
request_class: page_api::GetPageClass::Normal,
read_lsn: page_api::ReadLsn {
request_lsn: req_lsn,
not_modified_since_lsn: Some(mod_lsn),
},
rel,
block_numbers: blks,
};
self.req_tx.send(req).await?;
Ok(())
}
async fn recv_get_page(&mut self) -> anyhow::Result<(u64, Vec<Bytes>)> {
let resp = self.resp_rx.next().await.unwrap().unwrap();
anyhow::ensure!(
resp.status_code == page_api::GetPageStatusCode::Ok,
"unexpected status code: {}",
resp.status_code,
);
Ok((
resp.request_id.id,
resp.pages.into_iter().map(|p| p.image).collect(),
))
}
}
/// A rich gRPC Pageserver client.
struct RichGrpcClient {
inner: Arc<client_grpc::PageserverClient>,
requests: FuturesUnordered<
Pin<Box<dyn Future<Output = anyhow::Result<page_api::GetPageResponse>> + Send>>,
>,
}View on GitHub (pinned to 8f60b04da4)
Solutions
- Check the pageserver log at the failure timestamp for the concrete rejection reason
- Rebuild or redeploy pagebench from the same commit as the pageserver so the page_api types match
- Re-run timeline discovery and confirm the tenant is active with WAL beyond the requested LSNs
- Reduce the bench to a single timeline to identify which target produces the non-Ok status
Example fix
// before
anyhow::ensure!(
resp.status_code == page_api::GetPageStatusCode::Ok,
"unexpected status code: {}",
resp.status_code,
);
// after: distinguish statuses instead of treating all alike
match resp.status_code {
page_api::GetPageStatusCode::Ok => {}
page_api::GetPageStatusCode::NotModified => {
// no image sent for this request; handle or skip explicitly
}
code => anyhow::bail!("unexpected status code: {code}"),
} Defensive patterns
Strategy: try-catch
Type guard
fn is_ok_status(code: page_api::GetPageStatusCode) -> bool {
matches!(code, page_api::GetPageStatusCode::Ok)
} Try / catch
let (id, pages) = match client.recv_get_page().await {
Ok(v) => v,
Err(err) if err.to_string().starts_with("unexpected status code") => {
// log worker context, drop this request, keep the bench running
tracing::warn!(?err, "non-Ok GetPage status; skipping request");
continue;
}
Err(err) => return Err(err),
}; Prevention
- Pin pagebench and pageserver to the same neon revision in bench environments
- Warm up the timeline (ingest WAL) before measuring
- Log the request LSN and relation alongside the failing status for triage
When it happens
Trigger: The bench requests pages for relations or LSNs the pageserver cannot serve as images: keys that do not exist at the requested LSN, data GC'd past the retention horizon, a sharded-tenant routing mismatch, or a page_api schema mismatch between the pagebench build and the running pageserver.
Common situations: Running pagebench from one neon commit against a pageserver built from another after GetPage protocol changes; benching a freshly created timeline before it has ingested WAL; requesting an LSN beyond the timeline end.
Related errors
- {} response
- {err}
- no response
- no grpc_url for shard {shard_index}
- invalid shard URL {url}: must use gRPC
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/aaacbf1bf5339000.
Report an issue: GitHub.