nautechsystems/nautilus_trader · error · anyhow::Error

URI {path} uses non-remote scheme {} for remote catalog at {

Error message

URI {path} uses non-remote scheme {} for remote catalog at {}

What it means

The persistence catalog is backed by a remote object store (S3, GCS, etc.), and it validates that any URI passed to `object_store_path` uses a recognized remote scheme. When the parsed path's scheme (e.g. `file`, `http`, `sftp`, or a relative path defaulting to `file`) is not in the remote-scheme allowlist, the catalog refuses to map it to an object-store path. This prevents accidentally writing parquet data to a local disk or unsupported store when the catalog is configured for a remote backend.

Source

Thrown at crates/persistence/src/backend/catalog.rs:3054

        let normalized_path = path.replace('\\', "/");

        if self.is_remote_uri() {
            if normalized_path.contains("://") {
                let path_under_root = self.remote_uri_object_path(&normalized_path)?;
                return Ok(self.path_under_base(&path_under_root));
            }

            return Ok(self.path_under_base(&normalized_path));
        }

        Ok(self.path_without_local_base(&normalized_path))
    }

    fn remote_uri_object_path(&self, path: &str) -> anyhow::Result<String> {
        let path_url = url::Url::parse(path)
            .map_err(|e| anyhow::anyhow!("Failed to parse object store URI {path}: {e}"))?;
        if !is_remote_uri_scheme(path_url.scheme()) {
            anyhow::bail!(
                "URI {path} uses non-remote scheme {} for remote catalog at {}",
                path_url.scheme(),
                self.original_uri,
            );
        }

        let catalog_root = remote_store_root_url(&self.original_uri)?;
        let path_root = remote_store_root_url(path)?;
        if catalog_root.as_str().trim_end_matches('/') != path_root.as_str().trim_end_matches('/') {
            anyhow::bail!(
                "Cross-store URI {path} (root {}) does not belong to catalog rooted at {} ({})",
                path_root.as_str().trim_end_matches('/'),
                self.original_uri,
                catalog_root.as_str().trim_end_matches('/'),
            );
        }

        // The URL crate keeps the path component percent-encoded (e.g. `%5E`),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Fix the path to use the same remote scheme as the catalog (e.g. `s3://bucket/path/to/file.parquet`) instead of `file://` or a relative path.
  2. Check for typos in the URI scheme (`s3`, `gs`, `azure`, per the library's supported remote schemes) and correct it.
  3. If a local catalog is intended, construct the catalog with the local URI so the remote validation path is not used.

Example fix

// before
catalog.object_store_path("file:///home/user/data/quotes.parquet");
// after
catalog.object_store_path("s3://my-bucket/data/quotes.parquet");
Defensive patterns

Strategy: validation

Validate before calling

// Rust
fn is_remote(path: &str) -> bool {
    url::Url::parse(path)
        .map(|u| matches!(u.scheme(), "s3" | "gs" | "az" | "abfs" | "memory"))
        .unwrap_or(false)
}
// call catalog.object_store_path(p) only if is_remote(p)

Type guard

fn assert_remote_uri(path: &str) -> Option<url::Url> {
    url::Url::parse(path).ok().filter(|u| !matches!(u.scheme(), "file" | "http" | "https"))
}

Prevention

When it happens

Trigger: Calling `catalog.object_store_path(path)` (via `remote_uri_object_path`) with a path whose URL scheme is not a remote scheme — e.g. a local `file:///data/catalog` path, a relative path like `./data`, an `http(s)://` URL, or a typo'd scheme like `s3x://bucket/key`.

Common situations: Developers mixing local and remote config: a catalog built with `s3://` URI but the queried/written path still points at a local file; path variables inherited from old local-catalog code; typos in bucket URIs (`s2://`); using `file://` URIs copied from local test setups against a production remote catalog.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/5a4c863357eff852. Report an issue: GitHub.