{"record":{"id":"ea2c6bab2128c701","repo":"neondatabase/neon","slug":"real-ext-name-is-not-found","errorCode":null,"errorMessage":"real_ext_name {} is not found","messagePattern":"real_ext_name (.+?) is not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/compute_api/src/spec.rs","lineNumber":425,"sourceCode":"        // If not, then it is not allowed to be used by this compute.\n        if !self\n            .public_extensions\n            .as_ref()\n            .is_some_and(|exts| exts.iter().any(|e| e == real_ext_name))\n            && !self\n                .custom_extensions\n                .as_ref()\n                .is_some_and(|exts| exts.iter().any(|e| e == real_ext_name))\n        {\n            return Err(anyhow::anyhow!(\"extension {} is not found\", real_ext_name));\n        }\n\n        match self.extension_data.get(real_ext_name) {\n            Some(_ext_data) => Ok((\n                real_ext_name.to_string(),\n                Self::build_remote_path(build_tag, pg_major_version, real_ext_name)?,\n            )),\n            None => Err(anyhow::anyhow!(\n                \"real_ext_name {} is not found\",\n                real_ext_name\n            )),\n        }\n    }\n\n    /// Get the architecture-specific portion of the remote extension path. We\n    /// use the Go naming convention due to Kubernetes.\n    fn get_arch() -> &'static str {\n        match std::env::consts::ARCH {\n            \"x86_64\" => \"amd64\",\n            \"aarch64\" => \"arm64\",\n            arch => arch,\n        }\n    }\n\n    /// Build a [`RemotePath`] for an extension.\n    fn build_remote_path(","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/compute_api/src/spec.rs#L407-L443","documentation":"Thrown by RemoteExtSpec::get_ext() in neon's compute_api when the extension name passed both the library_index mapping (if applicable) and the public/custom allow-list, but is absent from RemoteExtSpec.extension_data (the map holding control_data and archive_path used to build the remote download path). Reaching it means the RemoteExtSpec is internally inconsistent: an extension is advertised in the allow-list but has no download metadata.","triggerScenarios":"get_ext(name, ...) where name appears in public_extensions/custom_extensions but has no entry in extension_data. This requires malformed or version-skewed control-plane input: the allow-list and the data map are built from different extension sets.","commonSituations":"Control plane / compute version skew where a new extension was added to the availability list before its archive metadata was published; partially failed extension upload; hand-crafted RemoteExtSpec in tests that fills the lists but not extension_data.","solutions":["Dump the RemoteExtSpec and verify the failing extension has an extension_data entry; if missing, the spec itself is broken — report it as a control-plane/extension-registry inconsistency","Update the component that produced the spec (control plane or extension registry) so allow-list and extension_data stay in sync","As a workaround, remove the extension from the compute request until its data entry exists","If you build RemoteExtSpec in tests, populate extension_data for every allow-listed name"],"exampleFix":"// before (test/spec construction)\nspec.public_extensions = Some(vec![\"pgcrypto\".into()]);\n// extension_data left empty -> error 104\n\n// after\nspec.public_extensions = Some(vec![\"pgcrypto\".into()]);\nspec.extension_data.insert(\n    \"pgcrypto\".into(),\n    ExtensionData { control_data: Default::default(), archive_path: \"ext/pgcrypto.tar.zst\".into() },\n);","handlingStrategy":"validation","validationCode":"// Detect the inconsistent state up front:\nfn spec_is_consistent(spec: &RemoteExtSpec) -> Vec<String> {\n    spec.public_extensions.iter().flatten()\n        .chain(spec.custom_extensions.iter().flatten())\n        .filter(|e| !spec.extension_data.contains_key(*e))\n        .cloned()\n        .collect()\n}","typeGuard":null,"tryCatchPattern":"// Treat as a spec-building bug, not a user error:\nif let Err(e) = spec.get_ext(name, is_lib, tag, ver) {\n    if e.to_string().contains(\"real_ext_name\") {\n        tracing::error!(\"RemoteExtSpec inconsistent: {e}\");\n    }\n    return Err(e);\n}","preventionTips":["In producers of RemoteExtSpec, build allow-lists from extension_data.keys() so they cannot drift","Add a round-trip test asserting every allow-listed name has extension_data","Version-check control plane vs compute when upgrading the extension registry"],"tags":["neon","compute-api","extensions","data-inconsistency","postgres"],"backgroundTag":"schema-validation-failed","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}