hashicorp/terraform · error
sasToken cannot be empty
Error message
sasToken cannot be empty
What it means
Thrown by the Azure remote-state backend's buildClient when config.SasToken is non-empty (so the SAS branch was selected) but strings.TrimSpace(sasToken) is empty, meaning the supplied value was only whitespace. The non-empty check that selected the branch passes for whitespace-only strings, so this guard catches the degenerate case explicitly.
Solutions
- Provide a complete, non-whitespace SAS token (typically starts with 'sv=' or '?' followed by key=value pairs).
- Trim and validate the secret at the CI/secret store before injecting it, so whitespace-only values fail earlier.
- If you did not mean to use SAS, unset sas_token / ARM_SAS_TOKEN so a different auth branch (access key, AAD, ARM-fallback) is selected.
- Prefer use_azuread_authentication=true with proper SP credentials for less error-prone auth.
Example fix
# before: secret resolved to spaces export ARM_SAS_TOKEN=" " # -> sasToken cannot be empty # after: real token (with or without leading '?') export ARM_SAS_TOKEN="sv=2021-06-08&ss=bfqt&srt=sco&sp=rwdlacupiydd&se=...&sig=..."
Defensive patterns
Strategy: validation
Validate before calling
// Validate a SAS token env before terraform runs.
func validSAS(v string) error {
if strings.TrimSpace(v) == "" { return fmt.Errorf("SAS token is empty/whitespace") }
return nil
} Type guard
null
Try / catch
client, err := azure.NewClient(ctx, cfg)
if err != nil && strings.Contains(err.Error(), "sasToken cannot be empty") {
// re-check the injected secret and surface a clearer message
} Prevention
- Inject SAS tokens via a secret manager that rejects whitespace-only values.
- Prefer use_azuread_authentication over SAS for less error-prone auth.
- If you do not need SAS, unset ARM_SAS_TOKEN so a different auth branch is taken.
When it happens
Trigger: sas_token in the azurerm backend block, or the matching env var (ARM_SAS_TOKEN), is set to a string of only spaces, tabs, or newlines. The switch case config.SasToken != "" is taken, then the trim check fails.
Common situations: A CI secret that resolved to whitespace (e.g. a quoted space in the CI variable definition), copy-paste of just the leading '?' of a SAS query string without the rest, or a templating system that left blanks. Also seen when the env var inherited a stray trailing newline combined with no real token.
Related errors
- unable to build authorizer for Resource Manager API: %+v
- unable to build authorizer for Storage API: %+v
- building Storage Accounts client: %+v
- Error loading credentials
- One of `access_key`, `sas_token`, `use_azuread_auth` and…
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/5cf23ec9d975fe39.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/azure/api_client.go:57
accessKey string
sasToken string
azureAdStorageAuth auth.Authorizer
}
func buildClient(ctx context.Context, config BackendConfig) (*Client, error) {
client := Client{
environment: config.AuthConfig.Environment,
storageAccountName: config.StorageAccountName,
}
var armAuthRequired bool
switch {
case config.AccessKey != "":
client.accessKey = config.AccessKey
case config.SasToken != "":
sasToken := config.SasToken
if strings.TrimSpace(sasToken) == "" {
return nil, fmt.Errorf("sasToken cannot be empty")
}
client.sasToken = strings.TrimPrefix(sasToken, "?")
case config.UseAzureADAuthentication:
var err error
client.azureAdStorageAuth, err = auth.NewAuthorizerFromCredentials(ctx, *config.AuthConfig, config.AuthConfig.Environment.Storage)
if err != nil {
return nil, fmt.Errorf("unable to build authorizer for Storage API: %+v", err)
}
default:
// AAD authentication (ARM scope) is required only when no auth method is specified, which falls back to listing the access key via ARM API.
armAuthRequired = true
}
// If `config.LookupBlobEndpoint` is true, we need to authenticate with ARM to lookup the blob endpoint
if config.LookupBlobEndpoint {
armAuthRequired = true
}
View on GitHub (pinned to d32a084675)