neondatabase/neon · error

no timelines found

Error message

no timelines found

What it means

idle_streams picks a victim timeline by calling targets::discover with limit_to_first_n_targets: Some(1). If the pageserver management API returns an empty timeline list, timelines.first() is None and the command fails with 'no timelines found' before opening any stream.

Source

Thrown at pageserver/pagebench/src/cmd/idle_streams.rs:58

async fn main_impl(args: Args) -> anyhow::Result<()> {
    // Discover a tenant and timeline to use.
    let mgmt_api_client = Arc::new(pageserver_client::mgmt_api::Client::new(
        reqwest::Client::new(),
        args.http_server.clone(),
        None,
    ));
    let timelines: Vec<TenantTimelineId> = crate::util::cli::targets::discover(
        &mgmt_api_client,
        crate::util::cli::targets::Spec {
            limit_to_first_n_targets: Some(1),
            targets: None,
        },
    )
    .await?;
    let ttid = timelines
        .first()
        .ok_or_else(|| anyhow!("no timelines found"))?;

    // Set up the initial client.
    let endpoint = Endpoint::from_shared(args.server.clone())?;

    let connect = async || {
        pageserver_page_api::Client::new(
            endpoint.connect().await?,
            ttid.tenant_id,
            ttid.timeline_id,
            ShardIndex::unsharded(),
            None,
            None,
        )
    };

    let mut client = connect().await?;
    let mut streams = Vec::with_capacity(args.count);

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Verify the management API endpoint, e.g. curl http://<host>:6400/v1/tenant returns a non-empty list
  2. Create or attach a tenant and timeline and wait until it reports active
  3. Re-run idle_streams once the tenant appears in the list

Example fix

# before
idle_streams --mgmt-api-endpoint http://wrong-host:6400 ...
# after
# 1) confirm the tenant list is non-empty
curl -s http://localhost:6400/v1/tenant | jq length   # must be > 0
# 2) run the bench against the same endpoint
idle_streams --mgmt-api-endpoint http://localhost:6400 ...
Defensive patterns

Strategy: validation

Validate before calling

let timelines = crate::util::cli::targets::discover(
    &mgmt_api_client,
    Spec { limit_to_first_n_targets: Some(1), targets: None },
).await?;
if timelines.is_empty() {
    anyhow::bail!("no timelines on this pageserver; create or attach a tenant first");
}

Try / catch

let ttid = match timelines.first() {
    Some(ttid) => *ttid,
    None => {
        eprintln!("no timelines found: check --mgmt-api-endpoint and tenant state");
        return Err(anyhow!("no timelines found"));
    }
};

Prevention

When it happens

Trigger: Running idle_streams against a pageserver with zero attached tenants; pointing --mgmt-api-endpoint at the wrong host or at the page_service port so the tenant list comes back empty; all tenants deleted or in a state excluded from listing.

Common situations: A fresh dev or staging pageserver before any tenant is created; after tenant migration or deletion; port confusion between the management API and other listeners.

Related errors


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