risingwavelabs/risingwave · error · SinkError::DeltaLake

path should start with 's3://','s3a://'(s3) ,gs://(gcs) or f

Error message

path should start with 's3://','s3a://'(s3) ,gs://(gcs) or file://(local)

What it means

get_table_url classifies the deltalake location by prefix into S3 (s3://, s3a://), GCS (gs://) or Local (file://). A location with none of these prefixes cannot be routed to a storage handler, so it raises SinkError::DeltaLake listing the accepted schemes.

Source

Thrown at src/connector/src/sink/deltalake.rs:137

                    })?,
                );
                deltalake::gcp::register_handlers(None);
                let url = Url::parse(&gcs_path).map_err(|e| SinkError::DeltaLake(anyhow!(e)))?;
                deltalake::open_table_with_storage_options(url, storage_options).await?
            }
        };
        Ok(table)
    }

    fn get_table_url(path: &str) -> Result<DeltaTableUrl> {
        if path.starts_with("s3://") || path.starts_with("s3a://") {
            Ok(DeltaTableUrl::S3(path.to_owned()))
        } else if path.starts_with("gs://") {
            Ok(DeltaTableUrl::Gcs(path.to_owned()))
        } else if let Some(path) = path.strip_prefix("file://") {
            Ok(DeltaTableUrl::Local(path.to_owned()))
        } else {
            Err(SinkError::DeltaLake(anyhow!(
                "path should start with 's3://','s3a://'(s3) ,gs://(gcs) or file://(local)"
            )))
        }
    }

    async fn build_delta_lake_config_for_aws(&self) -> Result<HashMap<String, String>> {
        let mut storage_options = HashMap::new();
        storage_options.insert(AWS_ALLOW_HTTP.to_owned(), "true".to_owned());
        storage_options.insert(AWS_S3_ALLOW_UNSAFE_RENAME.to_owned(), "true".to_owned());
        let sdk_config = self.aws_auth_props.build_config().await?;
        let credentials = sdk_config
            .credentials_provider()
            .ok_or_else(|| {
                SinkError::Config(anyhow!(
                    "s3.access.key and s3.secret.key is required with aws s3"
                ))
            })?
            .as_ref()

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Prefix local paths with file:// (e.g. file:///absolute/path).
  2. Use s3:// or s3a:// for AWS S3 locations and gs:// for GCS locations.
  3. Check the configured location value for typos or a missing scheme; Azure/other backends are not supported here.

Example fix

// before
LOCATION = '/data/delta_table'
// after
LOCATION = 'file:///data/delta_table'
Defensive patterns

Strategy: validation

Validate before calling

const SCHEMES: [&str; 4] = ["s3://", "s3a://", "gs://", "file://"];
if !SCHEMES.iter().any(|s| location.starts_with(s)) {
    return Err(format!("deltalake location must start with one of {:?}", SCHEMES));
}

Prevention

When it happens

Trigger: create_deltalake_client calls get_table_url with a location lacking any recognized prefix — e.g. '/local/path' without file://, 'https://...', 'abfs://...', or an empty string.

Common situations: Passing a bare local path instead of file:///path; using an Azure Blob or other unsupported scheme; empty or mistyped location option.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/c1f43e0d284d96ba. Report an issue: GitHub.