{"record":{"id":"d4492bc2abf133ab","repo":"databendlabs/databend","slug":"input-uri-is-not-a-valid-huggingface-uri","errorCode":null,"errorMessage":"input uri is not a valid huggingface uri","messagePattern":"input uri is not a valid huggingface uri","errorType":"exception","errorClass":"InvalidInput","httpStatus":null,"severity":"error","filePath":"src/query/sql/src/planner/binder/location.rs","lineNumber":467,"sourceCode":"        network_config: None,\n    });\n\n    l.connection\n        .check()\n        .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?;\n\n    Ok(sp)\n}\n\n/// Huggingface uri looks like `hf://opendal/huggingface-testdata/path/to/file`.\n///\n/// We need to parse `huggingface-testdata` from the root.\nfn parse_huggingface_params(l: &mut UriLocation, root: String) -> Result<StorageParams> {\n    let (repo_name, root) = root\n        .trim_start_matches('/')\n        .split_once('/')\n        .ok_or_else(|| {\n            Error::new(\n                ErrorKind::InvalidInput,\n                \"input uri is not a valid huggingface uri\",\n            )\n        })?;\n\n    let sp = StorageParams::Huggingface(StorageHuggingfaceConfig {\n        repo_id: format!(\"{}/{repo_name}\", l.name),\n        repo_type: l\n            .connection\n            .get(\"repo_type\")\n            .cloned()\n            .unwrap_or_else(|| \"dataset\".to_string()),\n        revision: l\n            .connection\n            .get(\"revision\")\n            .cloned()\n            .unwrap_or_else(|| \"main\".to_string()),\n        root: root.to_string(),","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/sql/src/planner/binder/location.rs#L449-L485","documentation":"A Huggingface URI must look like hf://repo-owner/repo-name/path/...; parse_huggingface_params splits the normalized root on the first '/' to extract repo_name and inner root. If the path contains no '/', there is no repo/dataset name and the binder rejects the URI as invalid.","triggerScenarios":"Locations like 'hf://opendaling' or 'hf://opendaling/' — a repo name with no subsequent path segment — used in CREATE STAGE or COPY.","commonSituations":"Truncating the URI by copying only the repository URL without a trailing path; forgetting the dataset path after the repo; building URIs programmatically with missing path components.","solutions":["Include a path after the repo name: hf://<repo_type>/<repo_name>/<path>/ e.g. hf://opendal/huggingface-testdata/path/.","Verify the URI contains at least repo_name + '/' + path (the split requires a '/').","Check for URL-encoding or trimming that removed the trailing path segment."],"exampleFix":"// before\nCREATE STAGE s URL = 'hf://opendal/huggingface-testdata';\n// after\nCREATE STAGE s URL = 'hf://opendal/huggingface-testdata/data/';","handlingStrategy":"validation","validationCode":"// Rust\nfn is_valid_hf_uri(url: &str) -> bool {\n    url.starts_with(\"hf://\") && url[5..].split_once('/').map_or(false, |(_, rest)| rest.contains('/'))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always append a path segment after the repo name in hf:// URIs.","Test the URI in a SELECT before using it in CREATE STAGE.","Beware trailing-slash trimming in shell variables and templating."],"tags":["storage","huggingface","uri-parsing","validation"],"backgroundTag":"invalid-url-format","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}