benbjohnson/litestream · error

abs: cannot create azure blob client with SAS token: %w

Error message

abs: cannot create azure blob client with SAS token: %w

What it means

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.

Source

Thrown at abs/replica_client.go:171

	if accountKey == "" {
		accountKey = os.Getenv("LITESTREAM_AZURE_ACCOUNT_KEY")
	}

	// Create Azure Blob Storage client with appropriate authentication
	// Priority: SAS token > Shared key > Default credential chain
	var client *azblob.Client
	if sasToken != "" {
		// SAS token authentication - append token to endpoint URL
		if accountKey != "" {
			slog.Warn("both SAS token and account key configured, using SAS token")
		} else {
			slog.Debug("using SAS token authentication")
		}
		// Strip leading "?" if present to avoid double "?"
		endpointWithSAS := fmt.Sprintf("%s?%s", endpoint, strings.TrimPrefix(sasToken, "?"))
		client, err = azblob.NewClientWithNoCredential(endpointWithSAS, clientOptions)
		if err != nil {
			return fmt.Errorf("abs: cannot create azure blob client with SAS token: %w", err)
		}
	} else if accountKey != "" && c.AccountName != "" {
		// Use shared key authentication (existing behavior)
		slog.Debug("using shared key authentication")
		credential, err := azblob.NewSharedKeyCredential(c.AccountName, accountKey)
		if err != nil {
			return fmt.Errorf("abs: cannot create shared key credential: %w", err)
		}
		client, err = azblob.NewClientWithSharedKeyCredential(endpoint, credential, clientOptions)
		if err != nil {
			return fmt.Errorf("abs: cannot create azure blob client with shared key: %w", err)
		}
	} else {
		// Use default credential chain (similar to AWS SDK default credential chain)
		// This includes:
		// - Environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
		// - Managed Identity (for Azure VMs, App Service, etc.)
		// - Azure CLI credentials

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Regenerate the SAS token in the Azure portal/CLI and paste it cleanly (no quotes, no trailing '?')
  2. Confirm the endpoint is a full https URL so endpoint?token parses correctly
  3. Print/verify the token length and prefix (should start with 'sv=' or '?sv=') before configuring it
  4. If the token keeps failing, switch to shared-key or default-credential authentication instead

Example fix

// before
export LITESTREAM_ABS_SAS_TOKEN="""sv=2022-01-01&ss=b..."""  // stray quotes
// after
export LITESTREAM_ABS_SAS_TOKEN=sv=2022-01-01&ss=b...
Defensive patterns

Strategy: validation

Validate before calling

if t := os.Getenv("LITESTREAM_ABS_SAS_TOKEN"); t != "" && !strings.HasPrefix(strings.TrimPrefix(t, "?"), "sv=") {
    return errors.New("SAS token malformed (expected sv=... query params)")
}

Try / catch

if err := c.Init(ctx); err != nil {
    if strings.Contains(err.Error(), "with SAS token") {
        // regenerate token / check endpoint URL, then retry once
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/5c4e29b99fc99913. Report an issue: GitHub.