neondatabase/neon · critical

timeline id should be provided

Error message

timeline id should be provided

What it means

Neither spec.timeline_id nor the 'neon.timeline_id' GUC in cluster settings was present, so compute_ctl cannot identify which timeline the endpoint attaches to and aborts spec parsing. As with tenant id, this is the absence error; a malformed value produces the separate 'invalid timeline id' context error instead.

Source

Thrown at compute_tools/src/compute.rs:375

        let storage_auth_token = spec.storage_auth_token.clone();
        let tenant_id: TenantId = if let Some(tenant_id) = spec.tenant_id {
            tenant_id
        } else {
            let guc = spec
                .cluster
                .settings
                .find("neon.tenant_id")
                .ok_or(anyhow::anyhow!("tenant id should be provided"))?;
            TenantId::from_str(&guc).context("invalid tenant id")?
        };
        let timeline_id: TimelineId = if let Some(timeline_id) = spec.timeline_id {
            timeline_id
        } else {
            let guc = spec
                .cluster
                .settings
                .find("neon.timeline_id")
                .ok_or(anyhow::anyhow!("timeline id should be provided"))?;
            TimelineId::from_str(&guc).context(anyhow::anyhow!("invalid timeline id"))?
        };

        let endpoint_storage_addr: Option<String> = spec
            .endpoint_storage_addr
            .clone()
            .or_else(|| spec.cluster.settings.find("neon.endpoint_storage_addr"));
        let endpoint_storage_token = spec
            .endpoint_storage_token
            .clone()
            .or_else(|| spec.cluster.settings.find("neon.endpoint_storage_token"));

        let res = ParsedSpec {
            spec,
            pageserver_conninfo,
            safekeeper_connstrings,
            storage_auth_token,
            tenant_id,

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Set spec.timeline_id (preferred) or add "neon.timeline_id": "<32-hex-uuid>" to spec.cluster.settings
  2. Ensure the control plane stamps both tenant_id and timeline_id together when creating the spec
  3. Validate the spec has both ids (and both GUC fallbacks) before launch

Example fix

// before: neither field present -> error
// after
{ "timeline_id": "aa11bb22cc33dd44ee55ff6677889900", "cluster": { "settings": [ {"name": "neon.timeline_id", "value": "aa11bb22cc33dd44ee55ff6677889900" } ] } }
Defensive patterns

Strategy: validation

Validate before calling

let timeline_ok = spec.timeline_id.is_some()
    || spec.cluster.settings.find("neon.timeline_id").map(|s| !s.trim().is_empty()).unwrap_or(false);
if !timeline_ok { anyhow::bail!("spec rejected: timeline id missing"); }

Type guard

fn spec_has_timeline_id(spec: &ComputeSpec) -> bool {
    spec.timeline_id.is_some() || spec.cluster.settings.find("neon.timeline_id").is_some()
}

Prevention

When it happens

Trigger: ParsedSpec::try_from with spec.timeline_id == None and settings.find("neon.timeline_id") == None, immediately after the tenant_id lookup succeeds.

Common situations: Same family as the tenant_id error: hand-built specs, partial cplane migrations, version skew dropping the GUC, copy-paste specs where timeline_id was deleted.

Related errors


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