databendlabs/databend · error
path in URL must end with '/
Error message
path in URL must end with '/' {usage}. Got '{}'. What it means
parse_storage_params_from_uri requires that the path portion of the URI ends with a slash ('/') so it can be treated as a prefix/root by OpenDAL. If the URI path does not end with '/', it throws this InvalidInput error with the offending path and usage context embedded in the message.
Solutions
- Append a trailing '/' to the URL path, e.g. URL='s3://bucket/prefix/'
- If you intended the bucket root, use 's3://bucket/'
- Fix URI-building code to always end the path component with '/'
Example fix
-- before CREATE CONNECTION c STORAGE_TYPE='s3' URL='s3://mybucket/data'; -- after CREATE CONNECTION c STORAGE_TYPE='s3' URL='s3://mybucket/data/';
Defensive patterns
Strategy: validation
Validate before calling
if let Some(p) = url::Url::parse(storage_url)?.path() { /* ensure trailing slash */ }
let path = url::Url::parse(storage_url)?.path().to_string();
if !path.ends_with('/') && !path.is_empty() {
return Err(format!("storage URL path must end with '/': {storage_url}"));
} Try / catch
match err.kind() { ErrorKind::InvalidInput if msg.contains("path in URL must end with") => /* append '/' and retry */, _ => return Err(err) } Prevention
- Normalize storage URIs to end paths with '/' before DDL
- For bucket root, still write the trailing slash: s3://bucket/
- Add a unit test for URI building helpers asserting trailing slash
When it happens
Trigger: CREATE CONNECTION with URL='s3://bucket/prefix' (no trailing slash), or stage/connection DDL where the path component is a bare prefix; same for resolve_storage_params_from_uri callers.
Common situations: Writing 's3://bucket/data' instead of 's3://bucket/data/'; generating URIs programmatically and dropping the trailing slash.
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
- endpoint_url is required for storage oss
- endpoint_url is required for storage cos
- protocol is not supported yet.
- can not use connection_name when create connection
- input connection is not a valid protocol
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/bf8b7a1451e58423.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/sql/src/planner/binder/location.rs:504
token: l.connection.get("token").cloned().unwrap_or_default(),
network_config: None,
});
l.connection
.check()
.map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?;
Ok(sp)
}
pub async fn parse_storage_params_from_uri(
l: &mut UriLocation,
usage: &str,
) -> Result<StorageParams> {
if !l.path.ends_with('/') {
return Err(Error::new(
ErrorKind::InvalidInput,
anyhow!("path in URL must end with '/' {usage}. Got '{}'.", l.path),
));
}
Ok(parse_uri_location(l).await?.0)
}
struct ParsedUriLocation {
root: String,
path: String,
protocol: Scheme,
}
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 {View on GitHub (pinned to 288d84d76e)