{"record":{"id":"3f5398b64e5993b1","repo":"juicedata/juicefs","slug":"unescape-access-key-s","errorCode":null,"errorMessage":"unescape access key: %s","messagePattern":"unescape access key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/object/ks3.go","lineNumber":405,"sourceCode":"\tbucket := hostParts[0]\n\tregion := hostParts[1][3:]\n\tregion = strings.TrimLeft(region, \"-\")\n\tvar pathStyle bool = defaultPathStyle()\n\tif strings.HasSuffix(uri.Host, \"ksyun.com\") || strings.HasSuffix(uri.Host, \"ksyuncs.com\") {\n\t\tregion = strings.TrimSuffix(region, \"-internal\")\n\t\tregion = ks3Regions[region]\n\t\tpathStyle = false\n\t} else if envRegion := os.Getenv(\"AWS_REGION\"); envRegion != \"\" {\n\t\tregion = envRegion\n\t}\n\tif region == \"\" {\n\t\tregion = \"us-east-1\"\n\t}\n\n\tvar err error\n\taccessKey, err = url.PathUnescape(accessKey)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unescape access key: %s\", err)\n\t}\n\tsecretKey, err = url.PathUnescape(secretKey)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unescape secret key: %s\", err)\n\t}\n\tawsConfig := &aws.Config{\n\t\tRegion:           region,\n\t\tEndpoint:         strings.SplitN(uri.Host, \".\", 2)[1],\n\t\tDisableSSL:       !ssl,\n\t\tHTTPClient:       httpClient,\n\t\tS3ForcePathStyle: pathStyle,\n\t\tCredentials:      credentials.NewStaticCredentials(accessKey, secretKey, token),\n\t}\n\n\treturn &ks3{bucket: bucket, s3: s3.New(awsConfig)}, nil\n}\n\nfunc init() {","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/object/ks3.go#L387-L423","documentation":"newKS3 percent-decodes the access key with url.PathUnescape so URL-escaped credentials are restored. This error wraps a PathUnescape failure, meaning the access key contains a malformed escape sequence such as a stray '%' not followed by two hex digits.","triggerScenarios":"Passing an access key containing an invalid percent-escape (e.g. 'abc%zz' or '100%') to newKS3 through the KS3 storage configuration.","commonSituations":"Credentials pasted from a URL where '%' appeared literally; double-encoding mistakes when building the config string.","solutions":["Remove or correctly encode the stray '%' in the access key ('%' may appear only as %XX hex escapes).","Pass the raw, un-escaped access key; escaping is only needed inside URL components.","If the key genuinely contains '%', percent-encode it as %25 so PathUnescape yields the literal character."],"exampleFix":"// before\naccessKey := \"AKIA100%\"\n// after\naccessKey := \"AKIA100%25\" // or use the raw key without URL escaping","handlingStrategy":"validation","validationCode":"func validPctEncoded(s string) bool {\n\tfor i := 0; i < len(s); i++ {\n\t\tif s[i] == '%' {\n\t\t\tif i+2 >= len(s) || !isHex(s[i+1]) || !isHex(s[i+2]) { return false }\n\t\t\ti += 2\n\t\t}\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":"if _, err := url.PathUnescape(accessKey); err != nil {\n\treturn fmt.Errorf(\"access key is not valid percent-encoding: %w\", err)\n}","preventionTips":["Pass raw credentials, not URL-escaped ones, when the source is not a URL.","Percent-encode literal '%' as %25 whenever credentials are embedded in a URL.","Store credentials in env vars or a secrets file instead of connection strings."],"tags":["object-storage","url-encoding","credentials"],"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"}