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

  1. Check the pageserver log at the failure timestamp for the concrete rejection reason
  2. Rebuild or redeploy pagebench from the same commit as the pageserver so the page_api types match
  3. Re-run timeline discovery and confirm the tenant is active with WAL beyond the requested LSNs
  4. 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

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


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/aaacbf1bf5339000. Report an issue: GitHub.