Introduction
Azure Service Bus message deferral allows postponing message processing by storing the message sequence number for later retrieval. When sequence numbers are lost or deferral logic fails, deferred messages cannot be retrieved, causing processing gaps.
Symptoms
Cannot find deferred message:
{
"error": {
"code": "MessageNotFound",
"message": "No message found with sequence number 12345678"
}
}Deferred messages stuck:
```bash $ az servicebus queue show \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --query 'countDetails.{Active:activeMessageCount,Deferred:transferMessageCount}'
# Shows messages in deferred state but not retrievable ```
Sequence number mismatch:
# Application error when receiving deferred message
"InvalidOperationException: The lock for sequence number 12345 has expired"Common Causes
- 1.Sequence number not stored - Application didn't persist sequence number
- 2.Sequence number lost - Storage failure or restart without persistence
- 3.Lock token expired - Deferral took too long, lock expired
- 4.Queue purge - Deferred messages removed during maintenance
- 5.Wrong sequence number - Using wrong number format or source
- 6.Session handling issue - Session-based deferral with wrong session ID
- 7.TTL expired - Deferred message TTL exceeded before retrieval
Step-by-Step Fix
- 1.Check logs for specific error messages
- 2.Verify configuration settings
- 3.Test network connectivity
- 4.Review recent changes
- 5.Apply corrective action
- 6.Verify the fix
Step 1: Check Deferred Message Count
```bash # Check queue statistics for deferred messages az servicebus queue show \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --query 'countDetails.{Active:activeMessageCount,Deferred:transferDeadLetterMessageCount,DLQ:deadLetterMessageCount}'
# Deferred messages appear in transferMessageCount ```
Step 2: Browse Deferred Messages
```bash # Peek deferred messages using Service Bus Explorer or PowerShell # Via PowerShell:
$namespace = "my-namespace" $queueName = "my-queue"
# Peek from deferred queue $messages = Peek-AzServiceBusMessage -NamespaceName $namespace -QueueName $queueName -DeferredQueue
foreach ($msg in $messages) { Write-Host "SequenceNumber: $($msg.SequenceNumber)" Write-Host "MessageId: $($msg.MessageId)" Write-Host "Body: $($msg.Body)" }
# Note: Sequence numbers required for retrieval ```
Step 3: Track Sequence Numbers
```bash # Store sequence numbers when deferring # Application pattern:
# When deferring: sequenceNumber = message.SequenceNumber; # Store in database or cache SaveToDatabase($"deferred:{queueName}:{sessionId}", sequenceNumber);
# When retrieving: storedSequenceNumber = LoadFromDatabase($"deferred:{queueName}:{sessionId}"); receiver.ReceiveDeferredMessage(storedSequenceNumber);
# Alternative: Use message properties for tracking message.ApplicationProperties["DeferredAt"] = DateTime.UtcNow; message.ApplicationProperties["OriginalSequenceNumber"] = sequenceNumber; ```
Step 4: Receive Deferred Messages
```bash # Receive by sequence number via PowerShell $receiver = New-AzServiceBusReceiver -NamespaceName my-namespace -QueueName my-queue
# Receive specific deferred message $message = Receive-AzServiceBusMessage -Receiver $receiver -SequenceNumber 12345678 -ReceiveMode PeekLock
# Complete the message Complete-AzServiceBusMessage -Receiver $receiver -LockToken $message.LockToken
# For multiple deferred messages $sequenceNumbers = @(12345678, 12345679, 12345680) foreach ($seq in $sequenceNumbers) { $msg = Receive-AzServiceBusMessage -Receiver $receiver -SequenceNumber $seq ProcessMessage($msg) } ```
Step 5: Fix Session-Based Deferral
```bash # For session-enabled queues az servicebus queue show \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --query 'requiresSession'
# Session-based deferral pattern: # 1. Accept session with session ID $sessionReceiver = AcceptSession($queuePath, sessionId);
# 2. Defer message within session context sequenceNumber = sessionReceiver.Defer(message);
# 3. Store sequence number with session ID SaveDeferredSequence(sessionId, sequenceNumber);
# 4. Retrieve from same session $sessionReceiver = AcceptSession($queuePath, sessionId); $deferredMsg = sessionReceiver.ReceiveDeferredMessage(sequenceNumber); ```
Step 6: Handle TTL on Deferred Messages
```bash # Check message TTL az servicebus queue show \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --query 'defaultMessageTimeToLive'
# Deferred messages still expire based on TTL # Extend TTL before deferring:
az servicebus queue update \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --default-message-time-to-live PT48H # 48 hours
# Or set per-message TTL message.TimeToLive = TimeSpan.FromHours(48); ```
Step 7: Implement Deferral Tracking Storage
```bash # Create storage for sequence numbers # Option 1: Azure Table Storage az storage table create \ --account-name mystorage \ --name DeferredMessages
# Store sequence number az storage entity insert \ --account-name mystorage \ --table-name DeferredMessages \ --entity PartitionKey=my-queue RowKey=12345678 SessionId=session-1 DeferredAt=2024-01-15T10:00:00Z
# Query deferred messages az storage entity query \ --account-name mystorage \ --table-name DeferredMessages \ --filter "PartitionKey eq 'my-queue'"
# Option 2: Redis cache az redis create \ --name deferred-cache \ --resource-group my-rg \ --location eastus ```
Step 8: Recover Lost Sequence Numbers
```bash # If sequence numbers lost, browse queue to find deferred messages # Use Service Bus Explorer or custom tool
# Peek all messages including deferred Get-AzServiceBusMessage -NamespaceName my-namespace -QueueName my-queue -PeekMode All
# Filter for deferred state foreach ($msg in $allMessages) { if ($msg.State -eq "Deferred") { Write-Host "Found deferred: Sequence=$($msg.SequenceNumber), MessageId=$($msg.MessageId)" # Save sequence number for retrieval } }
# Alternative: Reset queue to recover all messages (if acceptable) # This moves deferred back to active ```
Step 9: Set Up Deferral Monitoring
```bash # Monitor deferred message count az monitor metrics alert create \ --name sb-deferred-high \ --resource-group my-rg \ --scopes /subscriptions/SUB/resourceGroups/my-rg/providers/Microsoft.ServiceBus/namespaces/my-namespace \ --condition "avg TransferDeadLetterMessages > 100" \ --window-size 5m
Step 10: Implement Deferral Best Practices
```bash # Deferral workflow: # 1. Only defer when necessary (e.g., waiting for dependency) # 2. Always persist sequence number immediately # 3. Set appropriate TTL before deferring # 4. Implement timeout for deferred retrieval # 5. Have recovery mechanism for lost sequence numbers
# Deferral timeout pattern: deferredAt = DateTime.UtcNow; timeout = TimeSpan.FromHours(2);
if (DateTime.UtcNow - deferredAt > timeout) { // Abandon deferral, resubmit message }
# Monitor and alert on deferred queue buildup ```
Message States in Service Bus
| State | Description | Retrieval Method |
|---|---|---|
| Active | Ready for processing | Receive() |
| Deferred | Postponed, stored by seq# | ReceiveDeferred(seq#) |
| Scheduled | Scheduled for future | Appears at scheduled time |
| Dead-lettered | Failed processing | DLQ path |
Verification
```bash # After implementing sequence tracking # Test deferral and retrieval
# Defer a message az servicebus queue show \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --query 'countDetails'
# Verify sequence number stored in tracking storage az storage entity query \ --account-name mystorage \ --table-name DeferredMessages \ --filter "PartitionKey eq 'my-queue'"
# Retrieve deferred message # Verify message received and processed
# Check deferred count reduced az servicebus queue show \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --query 'countDetails.transferDeadLetterMessageCount'
# Should show reduced count ```
Prevention
To prevent Azure Service Bus message deferral issues from recurring, implement these proactive measures:
1. Monitor Deferred Message Count
groups:
- name: azure-servicebus
rules:
- alert: AzureServiceBusDeferredMessagesHigh
expr: |
azure_servicebus_deferred_message_count > 1000
for: 10m
labels:
severity: warning
annotations:
summary: "Azure Service Bus deferred message count exceeds 1000"2. Implement Message Tracking
```csharp // Store sequence numbers for deferred messages public class DeferredMessageTracker { private readonly BlobServiceClient _blobClient;
public async Task StoreSequenceNumber(string queueName, long sequenceNumber, string messageId) { var container = _blobClient.GetBlobContainerClient("deferred-messages"); var blob = container.GetBlobClient($"{queueName}/{messageId}");
await blob.UploadAsync(new BinaryData(new { SequenceNumber = sequenceNumber, DeferredAt = DateTime.UtcNow, MessageId = messageId })); }
public async Task<long?> GetSequenceNumber(string queueName, string messageId) { var container = _blobClient.GetBlobContainerClient("deferred-messages"); var blob = container.GetBlobClient($"{queueName}/{messageId}");
if (await blob.ExistsAsync()) { var data = await blob.DownloadContentAsync(); var info = data.Value.Content.ToObjectFromJson<DeferredMessageInfo>(); return info.SequenceNumber; } return null; } } ```
3. Set Up Dead Letter for Orphaned Messages
```bash # Configure max delivery count to move failed messages to DLQ az servicebus queue update \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --max-delivery-count 10
# Set TTL for messages az servicebus queue update \ --name my-queue \ --namespace-name my-namespace \ --resource-group my-rg \ --default-message-time-to-live P14D # 14 days ```
Best Practices Checklist
- [ ] Monitor deferred message count
- [ ] Implement message tracking
- [ ] Configure dead letter for orphaned messages
- [ ] Set appropriate TTL
- [ ] Process deferred messages promptly
- [ ] Document deferral use cases
Related Issues
- [Fix Azure Service Bus Dead Letter Queue Full](/articles/fix-azure-service-bus-dead-letter-queue-full)
- [Fix Azure Service Bus Session State Lost](/articles/fix-azure-service-bus-session-state-lost)
- [Fix Azure Service Bus Throttling](/articles/fix-azure-cosmos-db-throttling)
Related Articles
- [Technical troubleshooting: Fix Azure Aks Pod Crashloopbackoff Issue in Azure](azure-aks-pod-crashloopbackoff)
- [Technical troubleshooting: Fix Azure Api Management Policy Expression Runtime](azure-api-management-policy-expression-runtime-error)
- [Technical troubleshooting: Fix Azure App Configuration Feature Flag Not Refre](azure-app-configuration-feature-flag-not-refreshing)
- [Technical troubleshooting: Fix Azure App Service 503 Always On Disabled Issue](azure-app-service-503-always-on-disabled)
- [Technical troubleshooting: Fix Azure Application Gateway Err SSL Unrecognized](azure-application-gateway-err-ssl-unrecognized-name-alert)
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "Fix Azure Service Bus Message Deferral", "description": "Troubleshoot Service Bus deferred message issues. Track sequence numbers, implement deferral logic, and manage deferred queues.", "url": "https://www.fixwikihub.com/fix-azure-service-bus-message-deferral", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2026-04-03T15:13:45.604Z", "dateModified": "2026-04-03T15:13:45.604Z" } </script>