Microsoft Azureintermediate

How to Troubleshoot Azure Cost Management Export Issues

Diagnose and fix common problems with Azure cost data exports

12 min readUpdated January 2025

How to Troubleshoot Azure Cost Management Export Issues

Azure Cost Management exports are critical for automated billing analysis, but they can fail for various reasons—from permission issues to storage configuration problems. This guide provides systematic troubleshooting steps to diagnose and resolve the most common export issues, helping you maintain reliable cost data pipelines.

Prerequisites

Before troubleshooting, ensure you have:

  • Access to Azure portal with appropriate permissions (Cost Management Reader or higher)
  • Export configuration details (schedule name, storage account, container path)
  • Azure CLI or PowerShell installed (for advanced diagnostics)
  • Storage account access where exports are configured to write
  • Understanding of your export configuration (daily/monthly, scope, date range)

Understanding Azure Cost Management Exports

Cost Management exports automate the delivery of cost and usage data to Azure Storage. Key components:

  • Export schedule: Defines frequency (daily, weekly, monthly)
  • Scope: Subscription, Resource Group, Management Group, or Billing Account
  • Date range: Month-to-date, custom date range, or full history
  • Destination: Azure Storage account, container, and path
  • File format: CSV or Parquet
  • Permissions: Managed identity or manual RBAC assignments

Common Export Issues and Solutions

Issue 1: Export Never Runs or No Files Created

Symptoms:

  • Export shows "Created" status but never runs
  • No files appear in storage account
  • Export history shows no runs

Common Causes:

  1. Missing permissions on storage account
  2. Export not yet scheduled to run
  3. Storage account behind firewall/private endpoint
  4. Invalid storage path configuration

Solutions:

Step 1: Verify Export Schedule

# Check export configuration using Azure CLI
az costmanagement export show \
  --name "MyDailyCostExport" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID"

# Look for:
# - schedule.status: "Active"
# - schedule.recurrence: "Daily"
# - deliveryInfo.destination.container: correct name

Step 2: Check Storage Account Permissions

# List role assignments on storage account
az role assignment list \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RG/providers/Microsoft.Storage/storageAccounts/YOUR_STORAGE" \
  --output table

# Export needs "Storage Blob Data Contributor" role
# If missing, grant it:
az role assignment create \
  --role "Storage Blob Data Contributor" \
  --assignee-object-id "YOUR_EXPORT_MANAGED_IDENTITY_ID" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RG/providers/Microsoft.Storage/storageAccounts/YOUR_STORAGE"

Step 3: Verify Storage Account Network Access

  • Go to Azure Portal > Storage Account > Networking
  • Check if "Enabled from selected virtual networks and IP addresses" is selected
  • If yes, add exception: "Allow Azure services on the trusted services list to access this storage account"
  • Alternative: Add Cost Management service to allowed services

Step 4: Test Manual Run

# Trigger one-time export execution
az costmanagement export create \
  --name "TestExport" \
  --type "Usage" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID" \
  --storage-account-id "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RG/providers/Microsoft.Storage/storageAccounts/YOUR_STORAGE" \
  --storage-container "costexports" \
  --timeframe "MonthToDate"

Issue 2: Export Fails with Permission Errors

Symptoms:

  • Export history shows "Failed" status
  • Error message: "The export does not have permission to write to the destination"
  • Error code: ExportFailedPermissionDenied

Solutions:

Step 1: Verify Managed Identity (If Used)

# Check if export has managed identity
az costmanagement export show \
  --name "MyExport" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID" \
  --query "identity"

# If using managed identity, ensure it has Storage Blob Data Contributor
# Get the managed identity principal ID from output above

Step 2: Grant Required RBAC Roles

Navigate to Storage Account in Azure Portal:

  1. Go to Access Control (IAM) > Add role assignment
  2. Select role: Storage Blob Data Contributor
  3. Assign access to: Managed identity or User, group, or service principal
  4. Select: The export's managed identity or Cost Management service principal
  5. Click Save

Step 3: Check Storage Account Hierarchical Namespace

If using Azure Data Lake Storage Gen2:

# Verify if hierarchical namespace is enabled
az storage account show \
  --name "YOUR_STORAGE" \
  --resource-group "YOUR_RG" \
  --query "isHnsEnabled"

# If true, also grant "Storage Blob Data Contributor" at container level

Step 4: Verify No Conflicting Deny Assignments

# Check for Azure Policy deny assignments
az policy assignment list \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID" \
  --query "[?contains(displayName, 'Storage') || contains(displayName, 'Blob')]"

# Review any policies that might block write access

Issue 3: Export Files Are Empty or Incomplete

Symptoms:

  • Files appear in storage but contain no data or only headers
  • File size is abnormally small (< 1 KB)
  • CSV has headers but no rows

Solutions:

Step 1: Verify Scope Has Billable Resources

# Check if scope has any cost data
az costmanagement query \
  --type "Usage" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID" \
  --timeframe "MonthToDate" \
  --dataset-aggregation '{"totalCost":{"name":"Cost","function":"Sum"}}' \
  --dataset-grouping name="ResourceGroup" type="Dimension"

# If query returns no data, scope has no costs to export

Step 2: Check Date Range Configuration

  • Go to Cost Management > Exports > Select your export
  • Verify "Date range" setting:
    • Month-to-date: Only current month data
    • Custom date range: Check start/end dates are valid
    • Last month: Previous month only
  • If using custom dates, ensure range overlaps with actual resource usage

Step 3: Verify Export Type Matches Available Data

  • Actual Cost: Current charges (use this for most scenarios)
  • Amortized Cost: Spreads reservation costs over time
  • Usage: Raw usage data without pricing
  • Some scopes may not have data for all types

Step 4: Check for Filtering Issues

# Review export definition for filters
az costmanagement export show \
  --name "MyExport" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID" \
  --query "definition.dataSet.filter"

# Overly restrictive filters may exclude all data

Issue 4: Export Runs But Files Missing from Expected Location

Symptoms:

  • Export history shows "Completed" status
  • Files not in configured container/path
  • Files appear in unexpected location

Solutions:

Step 1: Verify Storage Path Configuration

# Check exact path configuration
az costmanagement export show \
  --name "MyExport" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID" \
  --query "deliveryInfo.destination"

# Output shows:
# - container: "costexports"
# - rootFolderPath: "reports/daily"

Step 2: Understand Default Naming Convention

Azure creates files with pattern:

{container}/{rootFolderPath}/{exportName}/{yyyyMMdd-yyyyMMdd}/{exportName}_{guid}.csv

Example:

costexports/reports/daily/DailyCostExport/20250101-20250131/DailyCostExport_12345678-90ab-cdef.csv

Step 3: Search All Containers

# List all containers in storage account
az storage container list \
  --account-name "YOUR_STORAGE" \
  --output table

# Search for recent files
az storage blob list \
  --container-name "costexports" \
  --account-name "YOUR_STORAGE" \
  --output table \
  --query "sort_by([?properties.lastModified >= '2025-01-01'], &properties.lastModified)"

Step 4: Check for Multiple Exports Writing to Same Path

  • Multiple exports with same rootFolderPath can cause confusion
  • Review all exports and ensure unique paths

Issue 5: Export Stops Running After Working Previously

Symptoms:

  • Export worked for weeks/months, then suddenly stops
  • Last successful run was days/weeks ago
  • No recent changes to configuration

Common Causes:

  1. Storage account key rotation
  2. Managed identity disabled or deleted
  3. Storage account moved/renamed
  4. Expired credentials (if using service principal)
  5. Subscription disabled/expired

Solutions:

Step 1: Check Storage Account Status

# Verify storage account exists and is accessible
az storage account show \
  --name "YOUR_STORAGE" \
  --resource-group "YOUR_RG"

# Check provisioning state should be "Succeeded"

Step 2: Re-validate Permissions

# Re-check role assignments (may have been removed)
az role assignment list \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RG/providers/Microsoft.Storage/storageAccounts/YOUR_STORAGE" \
  --all

# If missing, re-grant Storage Blob Data Contributor

Step 3: Recreate Export

If all else fails, delete and recreate export:

# Export current configuration first
az costmanagement export show \
  --name "MyExport" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID" > export-backup.json

# Delete export
az costmanagement export delete \
  --name "MyExport" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID"

# Recreate with same settings (using Azure Portal for easier setup)

Issue 6: Export Runs Daily But Contains Old Data

Symptoms:

  • Files created daily as scheduled
  • Data inside is days/weeks old
  • Missing recent cost data

Solutions:

Step 1: Understand Data Latency

Azure Cost Management data has inherent latency:

  • Consumption data: 24-48 hours delay
  • Marketplace charges: Up to 72 hours
  • Azure Hybrid Benefit: Can take 48+ hours
  • Reservation purchases: Immediate, but amortization takes time

This is normal—don't expect same-day cost data.

Step 2: Verify Date Range Configuration

# Check if using "MonthToDate" or fixed date range
az costmanagement export show \
  --name "MyExport" \
  --scope "/subscriptions/YOUR_SUBSCRIPTION_ID" \
  --query "definition.timeframe"

# "MonthToDate" should include current month up to yesterday
# Fixed date ranges don't move forward

Step 3: Check for Overwrite vs. Create New

  • Verify if export is configured to overwrite existing files
  • If overwriting, file might show old timestamp but have new data
  • Check file contents, not just modification date

Issue 7: Large Exports Fail or Time Out

Symptoms:

  • Export fails with timeout error
  • Works for small scopes but fails for large ones
  • Error: "Export execution exceeded time limit"

Solutions:

Step 1: Split Export by Scope

Instead of exporting entire billing account, create separate exports:

# Create per-subscription exports
for sub in $(az account list --query "[].id" -o tsv); do
  az costmanagement export create \
    --name "Export-${sub:0:8}" \
    --scope "/subscriptions/$sub" \
    --storage-account-id "YOUR_STORAGE_ACCOUNT_ID" \
    --storage-container "costexports" \
    --storage-directory "$sub" \
    --timeframe "MonthToDate" \
    --type "ActualCost" \
    --schedule-status "Active" \
    --schedule-recurrence "Daily"
done

Step 2: Use Parquet Format (More Efficient)

  • Parquet compresses better and transfers faster
  • Configure export to use Parquet instead of CSV
  • Azure Portal > Cost Management > Exports > Create/Edit > File format: Parquet

Step 3: Reduce Date Range

  • Use "MonthToDate" instead of custom 12-month range
  • Create separate exports for historical vs. current data
  • Historical: One-time export for past 12 months
  • Current: Daily/weekly export for current month

Step 4: Increase Timeout (If Using API)

# Python example with increased timeout
from azure.identity import DefaultAzureCredential
from azure.mgmt.costmanagement import CostManagementClient

credential = DefaultAzureCredential()
client = CostManagementClient(credential, timeout=600)  # 10 minutes

Advanced Diagnostics

Enable Diagnostic Logging for Storage Account

# Create Log Analytics workspace
az monitor log-analytics workspace create \
  --resource-group "YOUR_RG" \
  --workspace-name "storage-diagnostics"

# Enable storage account diagnostic logs
az monitor diagnostic-settings create \
  --resource "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RG/providers/Microsoft.Storage/storageAccounts/YOUR_STORAGE" \
  --name "export-diagnostics" \
  --logs '[{"category":"StorageWrite","enabled":true}]' \
  --workspace "storage-diagnostics"

# Query logs after next export attempt

Check Azure Service Health

# Check for Azure platform issues
az rest --method get \
  --url "https://management.azure.com/subscriptions/YOUR_SUBSCRIPTION_ID/providers/Microsoft.ResourceHealth/availabilityStatuses?api-version=2020-05-01" \
  --query "value[?properties.reasonChronicity == 'Persistent']"

# Visit Azure Status page: https://status.azure.com

Review Export Execution History Programmatically

# PowerShell: Get detailed export run history
$scope = "/subscriptions/YOUR_SUBSCRIPTION_ID"
$exportName = "MyExport"

$runs = Get-AzCostManagementExportExecutionHistory -Scope $scope -ExportName $exportName

$runs | Select-Object ExecutionType, Status, SubmittedTime, ProcessingStartTime, ProcessingEndTime, FileName | Format-Table

# Investigate failed runs
$failedRuns = $runs | Where-Object { $_.Status -eq "Failed" }
$failedRuns | Select-Object Status, Error

Best Practices to Prevent Issues

1. Use Managed Identity (Recommended)

  • More secure than storage account keys
  • No credential expiration
  • Automatic rotation

Configuration:

  1. Create export with managed identity enabled
  2. Grant Storage Blob Data Contributor to the managed identity
  3. No need to manage secrets

2. Implement Monitoring and Alerting

Create alert for export failures:

# Azure CLI: Create alert rule for failed exports
az monitor metrics alert create \
  --name "CostExportFailureAlert" \
  --resource-group "YOUR_RG" \
  --scopes "/subscriptions/YOUR_SUBSCRIPTION_ID" \
  --condition "count > 0" \
  --window-size 1d \
  --evaluation-frequency 1h \
  --description "Alert when cost export fails"

PowerShell: Monitor export status:

# Check export status daily
$scope = "/subscriptions/YOUR_SUBSCRIPTION_ID"
$export = Get-AzCostManagementExport -Scope $scope -ExportName "DailyCostExport"

if ($export.Schedule.Status -ne "Active") {
    Send-MailMessage -To "[email protected]" -Subject "Export Inactive" -Body "Export status: $($export.Schedule.Status)"
}

3. Implement Redundancy

Create backup export to secondary storage:

# Primary export to main storage
az costmanagement export create --name "Primary-Export" ...

# Backup export to secondary storage account
az costmanagement export create --name "Backup-Export" \
  --storage-account-id "/subscriptions/SUB_ID/resourceGroups/RG/providers/Microsoft.Storage/storageAccounts/BACKUP_STORAGE" ...

4. Document Export Configuration

Maintain documentation:

# export-config.yaml
exports:
  - name: DailyCostExport
    scope: /subscriptions/abc-123
    schedule: Daily at 02:00 UTC
    destination:
      storage: costmgmtstorage
      container: costexports
      path: daily
    format: CSV
    type: ActualCost
    managed_identity: /subscriptions/abc-123/resourceGroups/rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/export-identity

  - name: MonthlyAmortizedExport
    scope: /subscriptions/abc-123
    schedule: Monthly on 1st at 04:00 UTC
    destination:
      storage: costmgmtstorage
      container: costexports
      path: monthly
    format: Parquet
    type: AmortizedCost
    managed_identity: /subscriptions/abc-123/resourceGroups/rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/export-identity

5. Automate Export Validation

Python script to validate daily exports:

from azure.storage.blob import BlobServiceClient
from datetime import datetime, timedelta
import sys

# Configuration
storage_account = "costmgmtstorage"
container = "costexports"
connection_string = "DefaultEndpointsProtocol=https;..."

# Connect to storage
blob_service = BlobServiceClient.from_connection_string(connection_string)
container_client = blob_service.get_container_client(container)

# Check for today's export
today = datetime.now().strftime("%Y%m%d")
expected_prefix = f"daily/DailyCostExport/{today}"

blobs = list(container_client.list_blobs(name_starts_with=expected_prefix))

if not blobs:
    print(f"ERROR: No export found for {today}")
    sys.exit(1)

# Check file size
blob_size = blobs[0].size
if blob_size < 1024:  # Less than 1 KB
    print(f"WARNING: Export file unusually small: {blob_size} bytes")
    sys.exit(1)

print(f"SUCCESS: Export found - {blobs[0].name} ({blob_size} bytes)")

Troubleshooting Checklist

Use this checklist when troubleshooting export issues:

  • Export status is "Active" (not paused)
  • Storage account exists and is accessible
  • Storage Blob Data Contributor role assigned to export identity
  • Storage account firewall allows Cost Management service
  • Container name is correct (case-sensitive)
  • Root folder path is valid (no leading/trailing slashes)
  • Scope has billable resources in the date range
  • Date range configuration is correct (MonthToDate vs. custom)
  • No conflicting Azure Policy deny assignments
  • Managed identity (if used) is active and not deleted
  • Export execution history shows recent attempts
  • Storage account hasn't been moved to different subscription/region
  • No recent changes to storage account networking
  • Files searched in correct container and path
  • Data latency accounted for (24-48 hours normal)

When to Contact Azure Support

Contact Azure Support if:

  1. Export consistently fails despite correct permissions
  2. Data discrepancies between Cost Management UI and exported files
  3. Platform errors (HTTP 500, service unavailable)
  4. Suspected Azure service issue (check Azure Status first)
  5. Managed identity issues that can't be resolved
  6. Data loss or corruption in export files
  7. Unexpected charges appearing in exports

Before contacting support, gather:

  • Export configuration (JSON output from az costmanagement export show)
  • Export execution history (last 30 days)
  • Storage account diagnostic logs (if enabled)
  • Screenshots of errors
  • Correlation IDs from failed runs

Next Steps

After resolving export issues:

  1. Set up monitoring to detect future failures early
  2. Document your configuration for disaster recovery
  3. Automate validation to ensure exports complete successfully
  4. Review export scope to ensure capturing all necessary costs
  5. Optimize file format (consider Parquet for large exports)
  6. Implement data pipeline to process exports automatically

Related Resources

Frequently Asked Questions

Find answers to common questions

To verify your export's schedule configuration, utilize the Azure CLI. Run the command `az costmanagement export show --name 'MyExport' --scope '/subscriptions/YOURSUBSCRIPTIONID'`. Examine the output for `schedule.status` to ensure it is 'Active' and `schedule.recurrence` matches your intended frequency (e.g., Daily). If the export is not running as expected, check if it is properly scheduled and ensure there are no conflicting settings that may prevent the execution.

Need Professional Help?

Our team of experts can help you implement and configure these solutions for your organization.