neondatabase/neon · error
pageserver has less than limit_to_first_n_targets={limit} te
Error message
pageserver has less than limit_to_first_n_targets={limit} tenants What it means
Shared target discovery truncates the sorted timeline list to limit_to_first_n_targets and then requires that at least that many timelines existed. When the pageserver exposes fewer timelines than the limit, the bench aborts with the requested limit in the message. This fires even for limit=1 on an empty list, so it usually precedes the caller's own empty-list checks.
Source
Thrown at pageserver/pagebench/src/util/cli/targets.rs:26
pub(crate) limit_to_first_n_targets: Option<usize>,
pub(crate) targets: Option<Vec<TenantTimelineId>>,
}
pub(crate) async fn discover(
api_client: &Arc<mgmt_api::Client>,
spec: Spec,
) -> anyhow::Result<Vec<TenantTimelineId>> {
let mut timelines = if let Some(targets) = spec.targets {
targets
} else {
mgmt_api::util::get_pageserver_tenant_timelines_unsharded(api_client).await?
};
if let Some(limit) = spec.limit_to_first_n_targets {
timelines.sort(); // for determinism
timelines.truncate(limit);
if timelines.len() < limit {
anyhow::bail!("pageserver has less than limit_to_first_n_targets={limit} tenants");
}
}
info!("timelines:\n{:?}", timelines);
info!("number of timelines:\n{:?}", timelines.len());
Ok(timelines)
}
View on GitHub (pinned to 8f60b04da4)
Solutions
- Lower the limit to the number of timelines actually present; count them via the management API tenant list first
- Create or attach additional timelines if the bench genuinely needs N targets
- Pass explicit targets instead of a numeric limit where the bench allows it
Example fix
# before: server has 2 timelines pagebench basebackup --limit-to-first-n-targets 4 ... # after pagebench basebackup --limit-to-first-n-targets 2 ...
Defensive patterns
Strategy: validation
Validate before calling
let available = mgmt_api::util::get_pageserver_tenant_timelines_unsharded(&client).await?;
let limit = spec.limit_to_first_n_targets.unwrap_or(available.len());
anyhow::ensure!(
available.len() >= limit,
"need {limit} timelines, found {}",
available.len()
); Try / catch
let timelines = match discover(&client, spec).await {
Ok(ts) => ts,
Err(e) if e.to_string().contains("limit_to_first_n_targets") => {
eprintln!("lower --limit-to-first-n-targets or add timelines");
return Err(e);
}
Err(e) => return Err(e),
}; Prevention
- Count GET /v1/tenant timelines before choosing a limit
- Treat limits as derived from the environment, not hardcoded
- Prefer explicit target lists for reproducible benches
When it happens
Trigger: Passing --limit-to-first-n-targets N when the pageserver has fewer than N timelines; bench defaults (idle_streams uses 1) against a tenant-less pageserver; tenants deleted between discovery runs.
Common situations: Single-tenant dev pageservers used with multi-target bench profiles; stale scripts assuming old tenant counts; a wrong management API endpoint yielding an empty list that undershoots any limit of 1 or more.
Related errors
- There are no nodes to migrate to
- must specify exactly one target
- invalid connstring: {err}
- invalid scheme {scheme}
- no timelines found
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/7845839772268db8.
Report an issue: GitHub.