{"record":{"id":"4f3adcd6dab91b42","repo":"juicedata/juicefs","slug":"failed-to-create-azure-blob-client-with-sas-token","errorCode":null,"errorMessage":"Failed to create Azure blob client with SAS token: %v","messagePattern":"Failed to create Azure blob client with SAS token: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/object/azure.go","lineNumber":345,"sourceCode":"\t// Priority 2: No account key — use SAS token or managed identity\n\tif accountKey == \"\" {\n\t\tdomain := domainFromHost(hostParts)\n\n\t\tnormalized := normalizeSASToken(token)\n\n\t\tif normalized != \"\" {\n\t\t\tif domain == \"\" {\n\t\t\t\tvar err error\n\t\t\t\tif domain, err = autoWasbEndpoint(accountName, uri.Scheme, func(serviceURL string) (*azblob.Client, error) {\n\t\t\t\t\treturn azblob.NewClientWithNoCredential(serviceURL+\"?\"+normalized, nil)\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"Unable to get endpoint of container %s: %s\", containerName, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tsasURL := fmt.Sprintf(\"%s://%s.%s?%s\", uri.Scheme, accountName, domain, normalized)\n\t\t\tclient, err := azblob.NewClientWithNoCredential(sasURL, azblobOptions())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"Failed to create Azure blob client with SAS token: %v\", err)\n\t\t\t}\n\t\t\treturn &wasb{container: client.ServiceClient().NewContainerClient(containerName), azblobCli: client, cName: containerName, useTokenAuth: true}, nil\n\t\t}\n\n\t\ttokenCred, err := createAzureCredential()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"Failed to create Azure credential (managed identity/Azure CLI): %v\", err)\n\t\t}\n\t\tif domain == \"\" {\n\t\t\tif domain, err = autoWasbEndpoint(accountName, uri.Scheme, func(serviceURL string) (*azblob.Client, error) {\n\t\t\t\treturn azblob.NewClient(serviceURL, tokenCred, nil)\n\t\t\t}); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"Unable to get endpoint of container %s: %s\", containerName, err)\n\t\t\t}\n\t\t}\n\t\tserviceURL := fmt.Sprintf(\"%s://%s.%s\", uri.Scheme, accountName, domain)\n\t\tclient, err := azblob.NewClient(serviceURL, tokenCred, azblobOptions())\n\t\tif err != nil {","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/object/azure.go#L327-L363","documentation":"Thrown when azblob.NewClientWithNoCredential cannot construct an azblob.Client from the SAS URL (<scheme>://<account>.<domain>?<sas>). This happens after endpoint discovery succeeded, and indicates the assembled SAS URL is malformed.","triggerScenarios":"newWasb with SAS auth where the discovered domain combined with the account name and SAS query produces a URL the SDK rejects (empty/invalid domain discovered, invalid characters in SAS token).","commonSituations":"SAS token copied with stray whitespace/newlines; SAS token missing leading '?'; auto-discovered domain empty or garbage; non-URL-safe characters pasted from config files.","solutions":["Inspect the SAS token for whitespace, quotes, or a leading '?'; trim/normalize it.","Provide the endpoint with an explicit full domain so a bad auto-discovered domain is not used.","Validate the final URL parses with url.Parse before constructing the client.","Regenerate the SAS token from the Azure portal/CLI."],"exampleFix":"// before\nendpoint: \"azblob://acct.blob.core.windows.net? token=sv=...\"  (space inside token)\n// after\nendpoint: \"azblob://acct.blob.core.windows.net?sv=2020-02-10&ss=b&srt=sco\"","handlingStrategy":"validation","validationCode":"sas := strings.TrimSpace(sasToken)\nsas = strings.TrimPrefix(sas, \"?\")\nif sas == \"\" { return errors.New(\"empty SAS token\") }\nif _, err := url.Parse(\"https://acct.blob.core.windows.net?\" + sas); err != nil { return err }","typeGuard":null,"tryCatchPattern":"client, err := azblob.NewClientWithNoCredential(sasURL, nil)\nif err != nil {\n    return fmt.Errorf(\"bad SAS URL %q: %w\", redact(sasURL), err)\n}","preventionTips":["Trim whitespace and newlines from SAS tokens when loading config","Never include a leading '?' in the SAS token field","Store the token URL-encoded and validated at startup"],"tags":["azure","object-storage","sas-token","url-validation"],"backgroundTag":"invalid-url","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"}