hashicorp/terraform · error

listing Keys for %s: %+v

Error message

listing Keys for %s: %+v

What it means

AccountDetails.AccountKey (storage_client_helpers.go:66) calls the Azure Resource Manager `storageAccounts/ListKeys` operation (with Kerb expand) to fetch a storage account key for data-plane access. If the ARM call fails, the underlying error (permissions, throttling, connectivity, account not found) is wrapped via %+v.

Source

Thrown at internal/backend/remote-state/azure/storage_client_helpers.go:66

	// primaryQueueEndpoint is the Primary Queue Endpoint for the Data Plane API for this Storage Account
	// e.g. `https://{account}.queue.core.windows.net`
	primaryQueueEndpoint *string

	// primaryTableEndpoint is the Primary Table Endpoint for the Data Plane API for this Storage Account
	// e.g. `https://{account}.table.core.windows.net`
	primaryTableEndpoint *string
}

func (ad *AccountDetails) AccountKey(ctx context.Context, client *storageaccounts.StorageAccountsClient) (*string, error) {
	if ad.accountKey != nil {
		return ad.accountKey, nil
	}

	opts := storageaccounts.DefaultListKeysOperationOptions()
	opts.Expand = pointer.To(storageaccounts.ListKeyExpandKerb)
	listKeysResp, err := client.ListKeys(ctx, ad.StorageAccountId, opts)
	if err != nil {
		return nil, fmt.Errorf("listing Keys for %s: %+v", ad.StorageAccountId, err)
	}

	if model := listKeysResp.Model; model != nil && model.Keys != nil {
		for _, key := range *model.Keys {
			if key.Permissions == nil || key.Value == nil {
				continue
			}

			if *key.Permissions == storageaccounts.KeyPermissionFull {
				ad.accountKey = key.Value
				break
			}
		}
	}

	if ad.accountKey == nil {
		return nil, fmt.Errorf("unable to determine the Write Key for %s", ad.StorageAccountId)
	}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Grant the principal the Storage Account Key Operator Service Role (or Storage Account Contributor) on the target account.
  2. Verify storage_account_name and resource_group_name reference an existing account.
  3. Retry on 429/5xx; for persistent failures inspect the wrapped ARM error text.
  4. Confirm network/egress to management.azure.com is allowed.

Example fix

# before: principal has only Reader on the storage account
# after: assign the key-listing role
az role assignment create \
  --assignee <principal-id> \
  --role "Storage Account Key Operator Service Role" \
  --scope "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<acct>"
Defensive patterns

Strategy: retry

Validate before calling

# confirm the identity can list keys before terraform init
az role assignment list --assignee <principal-id> \
  --scope "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<acct>" \
  --query "[].roleDefinitionName" --output tsv | grep -qi "key operator\|storage account contributor" \
  || echo "WARN: principal may lack listKeys permission"

Type guard

// narrow a ListKeys error to decide retry vs abort
func isTransientListKeysErr(err error) bool {
    var rerr interface{ StatusCode() int }
    if errors.As(err, &rerr) {
        switch rerr.StatusCode() {
        case 408, 429, 500, 502, 503, 504:
            return true
        }
    }
    return false
}

Try / catch

// backoff/retry ListKeys for transient ARM failures, surface the rest
var key *string
err := backoff.Retry(func() error {
    k, e := ad.AccountKey(ctx, keysClient)
    if e != nil && isTransientListKeysErr(e) {
        return e
    }
    key = k
    return e
}, backoff.NewExponentialBackOff())

Prevention

When it happens

Trigger: The azurerm remote backend, using access-key-based data-plane auth, lists keys for the configured storage_account_name/resource_group_name when the authenticated identity lacks `Microsoft.Storage/storageAccounts/listKeys/action`, the account does not exist, ARM throttled (429), or the network to management.azure.com is unreachable.

Common situations: Service principal without Storage Account Key Operator Service Role / Storage Account Contributor; wrong subscription or resource group; transient ARM 429/5xx; egress/firewall blocking the ARM endpoint.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/262ca6059dee2718. Report an issue: GitHub.