databendlabs/databend · error

protocol is not supported yet.

Error message

protocol {protocol} is not supported yet.

What it means

The URI protocol is parsed into OpenDAL's Scheme enum, and Scheme::Custom (any scheme OpenDAL does not recognize as a built-in service) is rejected when resolving a UriLocation's parts. This error means the URL scheme in your stage/connection is not a supported storage protocol.

Solutions

  1. Use a supported scheme: s3, gcs, oss, cos, obs, azblob, fs, http(s), ipfs, webhdfs, huggingface, etc.
  2. Fix typos in the URL scheme
  3. Check Databend docs for the list of supported storage protocols for your version

Example fix

-- before
CREATE STAGE s URL='foo://bucket/path/';
-- after
CREATE STAGE s URL='s3://bucket/path/';
Defensive patterns

Strategy: validation

Validate before calling

let scheme = url::Url::parse(storage_url)?.scheme();
const SUPPORTED: &[&str] = &["s3","gcs","oss","cos","obs","azblob","fs","http","https","ipfs","webhdfs","huggingface"];
if !SUPPORTED.contains(&scheme) {
    return Err(format!("unsupported storage protocol: {scheme}"));
}

Try / catch

match err.kind() { ErrorKind::InvalidInput if msg.contains("is not supported yet") => /* fix scheme and retry */, _ => return Err(err) }

Prevention

When it happens

Trigger: CREATE STAGE / CREATE CONNECTION with an unknown or unsupported scheme, e.g. URL='foo://bucket/path', or a typo like 's33://bucket/'.

Common situations: Typos in the scheme; trying protocols Databend does not support (e.g. custom/internal schemes); copy-pasting a URI from another system.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/feecca0b7cef2cba. Report an issue: GitHub.

Appendix: source

Thrown at src/query/sql/src/planner/binder/location.rs:532

}

fn parse_uri_location_parts(l: &UriLocation) -> Result<ParsedUriLocation> {
    // Path ends with `/` means it's a directory, otherwise it's a file.
    // If the path is a directory, we will use this path as root.
    // If the path is a file, we will use `/` as root (which is the default value)
    let (root, path) = if l.path.ends_with('/') {
        (l.path.clone(), "/".to_string())
    } else {
        ("/".to_string(), l.path.clone())
    };
    let root = normalize_root(&root);
    let path = normalize_path(&path);

    let protocol = l.protocol.parse::<Scheme>()?;
    if let Scheme::Custom(_) = protocol {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            anyhow!("protocol {protocol} is not supported yet."),
        ));
    }

    Ok(ParsedUriLocation {
        root,
        path,
        protocol,
    })
}

pub async fn parse_uri_location(l: &mut UriLocation) -> Result<(StorageParams, String)> {
    let parts = parse_uri_location_parts(l)?;

    if l.connection.get("connection_name").is_some() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            anyhow!("can not use connection_name when create connection"),
        ));

View on GitHub (pinned to 288d84d76e)