neondatabase/neon · error

'REMOTE_STORAGE_CONFIG' environment variable must be set to

Error message

'REMOTE_STORAGE_CONFIG' environment variable must be set to a valid remote storage TOML config

What it means

The pageserver_ctl download-remote-object command builds its remote storage client exclusively from the REMOTE_STORAGE_CONFIG environment variable, which must hold the remote storage TOML (the same block the pageserver uses for its remote_storage configuration). If the variable is unset or not valid Unicode, the command fails immediately with this error.

Source

Thrown at pageserver/ctl/src/download_remote_object.rs:44

    /// Examples:
    ///   "wal/3aa8f.../00000001000000000000000A"
    ///   "pageserver/v1/tenants/<tenant_id>/timelines/<timeline_id>/layer_12345"
    pub remote_path: String,

    /// Path of the local file to create. Existing file will be overwritten.
    ///
    /// Examples:
    ///   "./segment"
    ///   "/tmp/layer_12345.parquet"
    pub output_file: Utf8PathBuf,
}

pub(crate) async fn main(cmd: &DownloadRemoteObjectCmd) -> anyhow::Result<()> {
    use remote_storage::{DownloadOpts, GenericRemoteStorage, RemotePath, RemoteStorageConfig};

    // Fetch remote storage configuration from the environment
    let config_str = std::env::var("REMOTE_STORAGE_CONFIG").map_err(|_| {
        anyhow::anyhow!(
            "'REMOTE_STORAGE_CONFIG' environment variable must be set to a valid remote storage TOML config"
        )
    })?;

    let config = RemoteStorageConfig::from_toml_str(&config_str)?;

    // Initialise remote storage client
    let storage = GenericRemoteStorage::from_config(&config).await?;

    // RemotePath must be relative – leading slashes confuse the parser.
    let remote_path_str = cmd.remote_path.trim_start_matches('/');
    let remote_path = RemotePath::from_string(remote_path_str)?;

    let cancel = CancellationToken::new();

    println!(
        "Downloading '{remote_path}' from remote storage bucket {:?} ...",
        config.storage.bucket_name()

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Export the variable with the remote storage TOML inline: REMOTE_STORAGE_CONFIG="$(cat remote_storage.toml)" pageserver_ctl download-remote-object ...
  2. Copy the remote_storage block from the pageserver's configuration; it must be valid TOML because RemoteStorageConfig::from_toml_str parses it next.
  3. For S3-like targets include the same bucket_name, region, and prefix_in_bucket values the pageserver uses, or the later download will address the wrong bucket.

Example fix

# before
pageserver_ctl download-remote-object --remote-path tenant-id/timeline-id/layer-file
# -> "'REMOTE_STORAGE_CONFIG' environment variable must be set ..."

# after
export REMOTE_STORAGE_CONFIG="$(cat /etc/neon/remote_storage.toml)"
pageserver_ctl download-remote-object --remote-path tenant-id/timeline-id/layer-file --output-file ./layer-file
Defensive patterns

Strategy: validation

Validate before calling

#!/usr/bin/env bash
# fail fast with a clear message before invoking the ctl
if [ -z "${REMOTE_STORAGE_CONFIG:-}" ]; then
  echo "REMOTE_STORAGE_CONFIG is empty; export the remote storage TOML first" >&2
  exit 1
fi
pageserver_ctl download-remote-object "$@"

Prevention

When it happens

Trigger: Running pageserver_ctl download-remote-object in a shell, cron job, or container where REMOTE_STORAGE_CONFIG was never exported.

Common situations: Expecting a --config flag instead of an env var; running the ctl from a different shell than the one that holds the pageserver config; CI or systemd units that do not forward the environment.

Related errors


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