neondatabase/neon · error · DownloadError::BadInput

Remote extensions storage is not configured

Error message

Remote extensions storage is not configured

What it means

ComputeNode::download_extension needs a base URL for the remote extension archive storage, taken from compute_ctl's -r/--remote-ext-base-url startup parameter (params.remote_ext_base_url). It was None, so the request fails immediately with DownloadError::BadInput before any network I/O. The process was started without extension storage configured, yet something asked to download an extension.

Source

Thrown at compute_tools/src/compute.rs:2419

            }

            format!("{{\"pg_stat_statements\": [{}]}}", result_rows.join(","))
        } else {
            "{{\"pg_stat_statements\": []}}".to_string()
        }
    }

    // download an archive, unzip and place files in correct locations
    pub async fn download_extension(
        &self,
        real_ext_name: String,
        ext_path: RemotePath,
    ) -> Result<u64, DownloadError> {
        let remote_ext_base_url =
            self.params
                .remote_ext_base_url
                .as_ref()
                .ok_or(DownloadError::BadInput(anyhow::anyhow!(
                    "Remote extensions storage is not configured",
                )))?;

        let ext_archive_name = ext_path.object_name().expect("bad path");

        let mut first_try = false;
        if !self
            .ext_download_progress
            .read()
            .expect("lock err")
            .contains_key(ext_archive_name)
        {
            self.ext_download_progress
                .write()
                .expect("lock err")
                .insert(ext_archive_name.to_string(), (Utc::now(), false));
            first_try = true;
        }

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Start compute_ctl with --remote-ext-base-url pointing at the extension storage (e.g. the public S3 web bucket) and restart the endpoint
  2. If extensions are not needed, stop requesting/downloading remote extensions for this compute (and remove them from shared_preload_libraries) so the code path is never hit
  3. For air-gapped installs, host a mirror of the extension archives and pass its URL

Example fix

# before
compute_ctl run --spec spec.json
# after
compute_ctl run --spec spec.json --remote-ext-base-url https://extensions.neon.tech/v0.2
Defensive patterns

Strategy: validation

Validate before calling

// Before requesting extensions, confirm the compute was started with storage
if compute.params.remote_ext_base_url.is_none() {
    anyhow::bail!("this compute has no --remote-ext-base-url; remote extensions unavailable");
}

Type guard

fn extensions_available(params: &ComputeParams) -> bool {
    params.remote_ext_base_url.is_some()
}

Try / catch

// The HTTP extension route already models this: return 503-style early instead of attempting the download
match compute.download_extension(name, path).await {
    Err(DownloadError::BadInput(e)) if e.to_string().contains("Remote extensions storage") => {
        (StatusCode::SERVICE_UNAVAILABLE, "remote extension storage not configured")
    }
    other => other,
}

Prevention

When it happens

Trigger: compute_ctl launched without the --remote-ext-base-url flag (or env equivalent feeding it), then the extension server / remote-extensions path calls download_extension() for a requested extension archive.

Common situations: Self-hosted or dev deployments that omit the public extension bucket URL; a docker/VM image whose startup script lost the flag; proxy/air-gapped installs pointing at a nonexistent mirror; spec asks for extensions on a build that intentionally disabled remote extensions.

Related errors


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