{"record":{"id":"5c4e29b99fc99913","repo":"benbjohnson/litestream","slug":"abs-cannot-create-azure-blob-client-with-sas-toke","errorCode":null,"errorMessage":"abs: cannot create azure blob client with SAS token: %w","messagePattern":"abs: cannot create azure blob client with SAS token: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"abs/replica_client.go","lineNumber":171,"sourceCode":"\tif accountKey == \"\" {\n\t\taccountKey = os.Getenv(\"LITESTREAM_AZURE_ACCOUNT_KEY\")\n\t}\n\n\t// Create Azure Blob Storage client with appropriate authentication\n\t// Priority: SAS token > Shared key > Default credential chain\n\tvar client *azblob.Client\n\tif sasToken != \"\" {\n\t\t// SAS token authentication - append token to endpoint URL\n\t\tif accountKey != \"\" {\n\t\t\tslog.Warn(\"both SAS token and account key configured, using SAS token\")\n\t\t} else {\n\t\t\tslog.Debug(\"using SAS token authentication\")\n\t\t}\n\t\t// Strip leading \"?\" if present to avoid double \"?\"\n\t\tendpointWithSAS := fmt.Sprintf(\"%s?%s\", endpoint, strings.TrimPrefix(sasToken, \"?\"))\n\t\tclient, err = azblob.NewClientWithNoCredential(endpointWithSAS, clientOptions)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"abs: cannot create azure blob client with SAS token: %w\", err)\n\t\t}\n\t} else if accountKey != \"\" && c.AccountName != \"\" {\n\t\t// Use shared key authentication (existing behavior)\n\t\tslog.Debug(\"using shared key authentication\")\n\t\tcredential, err := azblob.NewSharedKeyCredential(c.AccountName, accountKey)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"abs: cannot create shared key credential: %w\", err)\n\t\t}\n\t\tclient, err = azblob.NewClientWithSharedKeyCredential(endpoint, credential, clientOptions)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"abs: cannot create azure blob client with shared key: %w\", err)\n\t\t}\n\t} else {\n\t\t// Use default credential chain (similar to AWS SDK default credential chain)\n\t\t// This includes:\n\t\t// - Environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)\n\t\t// - Managed Identity (for Azure VMs, App Service, etc.)\n\t\t// - Azure CLI credentials","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/abs/replica_client.go#L153-L189","documentation":"Init attempts SAS-token authentication by appending the SAS token to the endpoint and calling azblob.NewClientWithNoCredential. If the Azure SDK cannot construct a client from that endpoint+token combination (malformed URL, invalid token format), the error is wrapped with this prefix and returned.","triggerScenarios":"A SAS token is configured but azblob.NewClientWithNoCredential fails — e.g. the SAS token contains invalid characters or is empty after the leading '?' is stripped, or the endpoint is malformed so the combined URL fails to parse.","commonSituations":"Pasting a SAS token that includes surrounding quotes or whitespace from the Azure portal; storing the token with the wrong env/config key so an empty or partial token is used; endpoint without scheme combined with the token producing an invalid URL.","solutions":["Regenerate the SAS token in the Azure portal/CLI and paste it cleanly (no quotes, no trailing '?')","Confirm the endpoint is a full https URL so endpoint?token parses correctly","Print/verify the token length and prefix (should start with 'sv=' or '?sv=') before configuring it","If the token keeps failing, switch to shared-key or default-credential authentication instead"],"exampleFix":"// before\nexport LITESTREAM_ABS_SAS_TOKEN=\"\"\"sv=2022-01-01&ss=b...\"\"\"  // stray quotes\n// after\nexport LITESTREAM_ABS_SAS_TOKEN=sv=2022-01-01&ss=b...","handlingStrategy":"validation","validationCode":"if t := os.Getenv(\"LITESTREAM_ABS_SAS_TOKEN\"); t != \"\" && !strings.HasPrefix(strings.TrimPrefix(t, \"?\"), \"sv=\") {\n    return errors.New(\"SAS token malformed (expected sv=... query params)\")\n}","typeGuard":null,"tryCatchPattern":"if err := c.Init(ctx); err != nil {\n    if strings.Contains(err.Error(), \"with SAS token\") {\n        // regenerate token / check endpoint URL, then retry once\n    }\n    return err\n}","preventionTips":["Regenerate SAS tokens from the portal with correct service (blob) and permissions","Strip quotes/whitespace; the token should start with sv= or ?sv=","Use a full https endpoint when combining with the token","Rotate tokens before expiry to avoid auth failures during Init"],"tags":["abs","azure","sas-token","authentication"],"backgroundTag":"module-init-failed","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}