neondatabase/neon · critical

tenant id should be provided

Error message

tenant id should be provided

What it means

Neither spec.tenant_id nor the 'neon.tenant_id' GUC in cluster settings was present, so compute_ctl cannot identify the tenant the endpoint belongs to and aborts spec parsing. Note this is the missing-field error; a present but malformed value fails later with a different 'invalid tenant id' context error.

Source

Thrown at compute_tools/src/compute.rs:365

                    .split(',')
                    .map(|str| str.to_string())
                    .collect()
            } else {
                vec![]
            }
        } else {
            spec.safekeeper_connstrings.clone()
        };

        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

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Set spec.tenant_id (preferred) or add "neon.tenant_id": "<32-hex-uuid>" to spec.cluster.settings
  2. Fix the control plane to always stamp tenant_id into the spec for compute endpoints
  3. Validate spec presence for tenant_id/timeline_id before starting compute_ctl

Example fix

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

Strategy: validation

Validate before calling

// Check both sources before parse
let tenant_ok = spec.tenant_id.is_some()
    || spec.cluster.settings.find("neon.tenant_id").map(|s| !s.trim().is_empty()).unwrap_or(false);
if !tenant_ok { anyhow::bail!("spec rejected: tenant id missing"); }

Type guard

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

Prevention

When it happens

Trigger: ParsedSpec::try_from with spec.tenant_id == None and settings.find("neon.tenant_id") == None. The GUC must hold a 32-hex-char UUID string; absence (not format) triggers this exact message.

Common situations: Hand-crafted spec.json for tests; cplane omitting tenant identification during migrations; renaming or dropping the GUC between control-plane and compute_ctl versions; empty-string GUC confused with a missing one (empty string goes to the 'invalid tenant id' path instead).

Related errors


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