{"record":{"id":"7f9114864d4e4271","repo":"neondatabase/neon","slug":"remote-extensions-are-not-configured","errorCode":null,"errorMessage":"Remote extensions are not configured","messagePattern":"Remote extensions are not configured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compute_tools/src/compute.rs","lineNumber":2616,"sourceCode":"\n        Ok(ext_version)\n    }\n\n    pub async fn prepare_preload_libraries(\n        &self,\n        spec: &ComputeSpec,\n    ) -> Result<RemoteExtensionMetrics> {\n        if self.params.remote_ext_base_url.is_none() {\n            return Ok(RemoteExtensionMetrics {\n                num_ext_downloaded: 0,\n                largest_ext_size: 0,\n                total_ext_download_size: 0,\n            });\n        }\n        let remote_extensions = spec\n            .remote_extensions\n            .as_ref()\n            .ok_or(anyhow::anyhow!(\"Remote extensions are not configured\"))?;\n\n        info!(\"parse shared_preload_libraries from spec.cluster.settings\");\n        let mut libs_vec = Vec::new();\n        if let Some(libs) = spec.cluster.settings.find(\"shared_preload_libraries\") {\n            libs_vec = libs\n                .split(&[',', '\\'', ' '])\n                .filter(|s| *s != \"neon\" && *s != \"databricks_auth\" && !s.is_empty())\n                .map(str::to_string)\n                .collect();\n        }\n        info!(\"parse shared_preload_libraries from provided postgresql.conf\");\n\n        // that is used in neon_local and python tests\n        if let Some(conf) = &spec.cluster.postgresql_conf {\n            let conf_lines = conf.split('\\n').collect::<Vec<&str>>();\n            let mut shared_preload_libraries_line = \"\";\n            for line in conf_lines {\n                if line.starts_with(\"shared_preload_libraries\") {","sourceCodeStart":2598,"sourceCodeEnd":2634,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/compute_tools/src/compute.rs#L2598-L2634","documentation":"The mirror of error 10: here params.remote_ext_base_url IS configured, but the ComputeSpec itself carries no remote_extensions block (spec.remote_extensions is None), so compute_ctl has no index of available extension archives and refuses. It means the local side is configured while the control-plane side of the contract is missing.","triggerScenarios":"download_all_remote_extensions runs with remote_ext_base_url set and spec.remote_extensions == None - typically a cplane that did not include the remote_extensions field in the spec, or version skew between control plane and compute_ctl.","commonSituations":"Upgrading compute_ctl ahead of/behind the control plane so the spec schema no longer matches; control plane disabling remote extensions while computes still pass the base URL; hand-written specs for testing.","solutions":["Ensure the control plane populates spec.remote_extensions (the extension index/version list) when it sends specs to this compute","Align control-plane and compute_ctl versions so the spec schema matches","If remote extensions are unwanted, also drop --remote-ext-base-url so the whole path short-circuits with zeroed metrics instead of erroring"],"exampleFix":"// before: base URL set, spec lacks the field -> Err(\"Remote extensions are not configured\")\n// after: spec fragment\n\"remote_extensions\": { \"library_index\": [ { \"ext\": [\"pg_uuidv7\"], \"lib\": [\"pg_uuidv7.so\"], \"control\": [\"pg_uuidv7.control\"], \"artifact\": \"ext/pg_uuidv7.tar.zst\" } ] }","handlingStrategy":"validation","validationCode":"// Both halves of the contract must hold before the download pass\nif params.remote_ext_base_url.is_some() && spec.remote_extensions.is_none() {\n    anyhow::bail!(\"compute has extension storage but spec lacks remote_extensions; version skew?\");\n}","typeGuard":"fn remote_extension_contract_holds(params: &ComputeParams, spec: &ComputeSpec) -> bool {\n    params.remote_ext_base_url.is_none() || spec.remote_extensions.is_some()\n}","tryCatchPattern":"// Degrade gracefully: zeroed metrics instead of an error (mirrors the base_url==None path)\nif spec.remote_extensions.is_none() {\n    warn!(\"spec has no remote_extensions index; skipping downloads\");\n    return Ok(RemoteExtensionMetrics { num_ext_downloaded: 0, largest_ext_size: 0, total_ext_download_size: 0 });\n}","preventionTips":["Keep control-plane and compute_ctl versions compatible; test spec/compute pairs together in CI","Make the cplane emit remote_extensions whenever computes are configured with a base URL","If you intentionally drop remote extensions, remove the flag on the compute side in the same change"],"tags":["rust","compute-ctl","extensions","spec","configuration","version-skew"],"backgroundTag":"missing-configuration","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}