{"record":{"id":"be44c2c9f49c096f","repo":"neondatabase/neon","slug":"tenant-id-should-be-provided","errorCode":null,"errorMessage":"tenant id should be provided","messagePattern":"tenant id should be provided","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compute_tools/src/compute.rs","lineNumber":365,"sourceCode":"                    .split(',')\n                    .map(|str| str.to_string())\n                    .collect()\n            } else {\n                vec![]\n            }\n        } else {\n            spec.safekeeper_connstrings.clone()\n        };\n\n        let storage_auth_token = spec.storage_auth_token.clone();\n        let tenant_id: TenantId = if let Some(tenant_id) = spec.tenant_id {\n            tenant_id\n        } else {\n            let guc = spec\n                .cluster\n                .settings\n                .find(\"neon.tenant_id\")\n                .ok_or(anyhow::anyhow!(\"tenant id should be provided\"))?;\n            TenantId::from_str(&guc).context(\"invalid tenant id\")?\n        };\n        let timeline_id: TimelineId = if let Some(timeline_id) = spec.timeline_id {\n            timeline_id\n        } else {\n            let guc = spec\n                .cluster\n                .settings\n                .find(\"neon.timeline_id\")\n                .ok_or(anyhow::anyhow!(\"timeline id should be provided\"))?;\n            TimelineId::from_str(&guc).context(anyhow::anyhow!(\"invalid timeline id\"))?\n        };\n\n        let endpoint_storage_addr: Option<String> = spec\n            .endpoint_storage_addr\n            .clone()\n            .or_else(|| spec.cluster.settings.find(\"neon.endpoint_storage_addr\"));\n        let endpoint_storage_token = spec","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/compute_tools/src/compute.rs#L347-L383","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Set spec.tenant_id (preferred) or add \"neon.tenant_id\": \"<32-hex-uuid>\" to spec.cluster.settings","Fix the control plane to always stamp tenant_id into the spec for compute endpoints","Validate spec presence for tenant_id/timeline_id before starting compute_ctl"],"exampleFix":"// before: neither field present -> error\n// after\n{ \"tenant_id\": \"0f0d8ce0f3aa11ed92dbf3c0c8b1a1a1\", \"timeline_id\": \"...\", \"cluster\": { \"settings\": [ {\"name\": \"neon.tenant_id\", \"value\": \"0f0d8ce0f3aa11ed92dbf3c0c8b1a1a1\" } ] } }","handlingStrategy":"validation","validationCode":"// Check both sources before parse\nlet tenant_ok = spec.tenant_id.is_some()\n    || spec.cluster.settings.find(\"neon.tenant_id\").map(|s| !s.trim().is_empty()).unwrap_or(false);\nif !tenant_ok { anyhow::bail!(\"spec rejected: tenant id missing\"); }","typeGuard":"fn spec_has_tenant_id(spec: &ComputeSpec) -> bool {\n    spec.tenant_id.is_some() || spec.cluster.settings.find(\"neon.tenant_id\").is_some()\n}","tryCatchPattern":null,"preventionTips":["Always stamp tenant_id and timeline_id together when generating specs (they fail as a pair)","Reject empty-string GUCs at the control plane so absence vs blank ambiguity disappears","Unit-test ParsedSpec::try_from against specs with each required field removed, to keep messages precise"],"tags":["rust","compute-ctl","spec","configuration","tenant-id","startup"],"backgroundTag":"missing-configuration","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}