{"record":{"id":"5a4c863357eff852","repo":"nautechsystems/nautilus_trader","slug":"uri-path-uses-non-remote-scheme-for-remote-ca","errorCode":null,"errorMessage":"URI {path} uses non-remote scheme {} for remote catalog at {}","messagePattern":"URI (.+?) uses non-remote scheme (.+?) for remote catalog at (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/persistence/src/backend/catalog.rs","lineNumber":3054,"sourceCode":"        let normalized_path = path.replace('\\\\', \"/\");\n\n        if self.is_remote_uri() {\n            if normalized_path.contains(\"://\") {\n                let path_under_root = self.remote_uri_object_path(&normalized_path)?;\n                return Ok(self.path_under_base(&path_under_root));\n            }\n\n            return Ok(self.path_under_base(&normalized_path));\n        }\n\n        Ok(self.path_without_local_base(&normalized_path))\n    }\n\n    fn remote_uri_object_path(&self, path: &str) -> anyhow::Result<String> {\n        let path_url = url::Url::parse(path)\n            .map_err(|e| anyhow::anyhow!(\"Failed to parse object store URI {path}: {e}\"))?;\n        if !is_remote_uri_scheme(path_url.scheme()) {\n            anyhow::bail!(\n                \"URI {path} uses non-remote scheme {} for remote catalog at {}\",\n                path_url.scheme(),\n                self.original_uri,\n            );\n        }\n\n        let catalog_root = remote_store_root_url(&self.original_uri)?;\n        let path_root = remote_store_root_url(path)?;\n        if catalog_root.as_str().trim_end_matches('/') != path_root.as_str().trim_end_matches('/') {\n            anyhow::bail!(\n                \"Cross-store URI {path} (root {}) does not belong to catalog rooted at {} ({})\",\n                path_root.as_str().trim_end_matches('/'),\n                self.original_uri,\n                catalog_root.as_str().trim_end_matches('/'),\n            );\n        }\n\n        // The URL crate keeps the path component percent-encoded (e.g. `%5E`),","sourceCodeStart":3036,"sourceCodeEnd":3072,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/persistence/src/backend/catalog.rs#L3036-L3072","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["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.","Check for typos in the URI scheme (`s3`, `gs`, `azure`, per the library's supported remote schemes) and correct it.","If a local catalog is intended, construct the catalog with the local URI so the remote validation path is not used."],"exampleFix":"// before\ncatalog.object_store_path(\"file:///home/user/data/quotes.parquet\");\n// after\ncatalog.object_store_path(\"s3://my-bucket/data/quotes.parquet\");","handlingStrategy":"validation","validationCode":"// Rust\nfn is_remote(path: &str) -> bool {\n    url::Url::parse(path)\n        .map(|u| matches!(u.scheme(), \"s3\" | \"gs\" | \"az\" | \"abfs\" | \"memory\"))\n        .unwrap_or(false)\n}\n// call catalog.object_store_path(p) only if is_remote(p)","typeGuard":"fn assert_remote_uri(path: &str) -> Option<url::Url> {\n    url::Url::parse(path).ok().filter(|u| !matches!(u.scheme(), \"file\" | \"http\" | \"https\"))\n}","tryCatchPattern":null,"preventionTips":["Build object-store paths from the catalog URI itself (join on the catalog root) rather than hardcoding `file://` or relative paths.","Validate URI schemes at config load time, before constructing the catalog.","Add a startup assertion that all configured data paths share the catalog's scheme."],"tags":["url","object-store","configuration","rust"],"backgroundTag":"invalid-url-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}