{"record":{"id":"38447959c5c70048","repo":"juicedata/juicefs","slug":"unescape-s-s","errorCode":null,"errorMessage":"unescape %s: %s","messagePattern":"unescape (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/sync.go","lineNumber":420,"sourceCode":"\t\tlogger.Fatalf(\"Can't parse %q: %s\", utils.RemovePassword(uri), utils.RemovePassword(err.Error()))\n\t}\n\tuser := u.User\n\tvar accessKey, secretKey string\n\tif user != nil {\n\t\taccessKey = user.Username()\n\t\tsecretKey, _ = user.Password()\n\t}\n\tname := strings.ToLower(u.Scheme)\n\n\tvar endpoint string\n\tif name == \"file\" {\n\t\tendpoint = u.Path\n\t} else if name == \"hdfs\" {\n\t\tendpoint = u.Host\n\t} else if name == \"jfs\" {\n\t\tendpoint, err = url.PathUnescape(u.Host)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unescape %s: %s\", u.Host, err)\n\t\t}\n\t\tif os.Getenv(endpoint) != \"\" {\n\t\t\tconf.Env[endpoint] = os.Getenv(endpoint)\n\t\t}\n\t} else if name == \"nfs\" {\n\t\tendpoint = u.Host + u.Path\n\t} else if !conf.NoHTTPS && supportHTTPS(name, u.Host) {\n\t\tendpoint = \"https://\" + u.Host\n\t} else {\n\t\tendpoint = \"http://\" + u.Host\n\t}\n\n\tisS3PathTypeUrl := isS3PathType(u.Host)\n\tif name == \"minio\" || name == \"s3\" && isS3PathTypeUrl {\n\t\t// bucket name is part of path\n\t\tendpoint += u.Path\n\t}\n","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/cmd/sync.go#L402-L438","documentation":"In `juicefs sync`, when a source/destination URI uses the `jfs` scheme, the volume name is carried in the URL host and may be percent-encoded. createSyncStorage calls url.PathUnescape on it; this error is returned when that unescaping fails, meaning the host component contains a malformed escape sequence such as `%zz` or a lone trailing `%`.","triggerScenarios":"Calling doSync (or createSyncStorage) with a `jfs://` URI whose host contains an invalid percent-escape, e.g. `jfs://vol%2name/` or `jfs://my%vol/`. Any byte after '%' that is not two hex digits causes url.PathUnescape to fail.","commonSituations":"Manually percent-encoding a volume name containing special characters and getting the encoding wrong; scripts building URIs with printf/shell substitutions that mangle '%'; copying a URL that was encoded with a non-URL scheme.","solutions":["Fix the URI so every '%' is followed by two hex digits, or remove unnecessary encoding entirely (e.g. `jfs://myvol` instead of `jfs://my%vol`)","Percent-encode properly: `%` itself becomes `%25` (use python3 -c 'import urllib.parse;print(urllib.parse.quote(name))')","If no special characters are in the volume name, use the raw name unencoded"],"exampleFix":"// before\njfs://vol%zz/subdir   # invalid escape\n// after\njfs://vol%25zz/subdir  # '%25' is an encoded '%'","handlingStrategy":"validation","validationCode":"u, err := url.Parse(uri)\nif err == nil && u.Scheme == \"jfs\" {\n\tif _, err := url.PathUnescape(u.Host); err != nil {\n\t\treturn fmt.Errorf(\"bad jfs URI host %q: %w\", u.Host, err)\n\t}\n}","typeGuard":"null","tryCatchPattern":"store, err := createSyncStorage(...)\nif err != nil && strings.HasPrefix(err.Error(), \"unescape \") {\n\t// fix the URI or surface a config error to the user\n}","preventionTips":["Percent-encode '%' as %25 when building jfs:// URIs programmatically","Avoid manual string concatenation of escape sequences into URIs","Test the URI with url.Parse + PathUnescape in scripts"],"tags":["url","sync","juicefs","escaping"],"backgroundTag":"invalid-url-format","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}