dotnet/orleans · error · ArgumentNullException
ReceiptHandle
Error message
ReceiptHandle
What it means
Thrown by SQSStorage.DeleteMessage when message.ReceiptHandle is null/empty/whitespace. SQS deletion requires a valid ReceiptHandle (issued when the message was received); without it AWS cannot identify which reception to acknowledge, so the provider rejects the call before contacting SQS.
Source
Thrown at src/AWS/Orleans.Streaming.SQS/Storage/SQSStorage.cs:219
ReportErrorAndRethrow(exc, "GetMessages");
}
throw new InvalidOperationException("Unable to retrieve messages from the queue.");
}
/// <summary>
/// Delete a message from SQS queue
/// </summary>
/// <param name="message">The message to be deleted</param>
/// <returns></returns>
public async Task DeleteMessage(SQSMessage message)
{
try
{
if (message == null)
throw new ArgumentNullException(nameof(message));
if (string.IsNullOrWhiteSpace(message.ReceiptHandle))
throw new ArgumentNullException(nameof(message.ReceiptHandle));
if (string.IsNullOrWhiteSpace(queueUrl))
throw new InvalidOperationException("Queue not initialized");
await sqsClient.DeleteMessageAsync(
new DeleteMessageRequest { QueueUrl = queueUrl, ReceiptHandle = message.ReceiptHandle });
}
catch (Exception exc)
{
ReportErrorAndRethrow(exc, "DeleteMessage");
}
}
private void ReportErrorAndRethrow(Exception exc, string operation)
{
LogErrorSQSOperation(exc, operation, QueueName);
throw new AggregateException($"Error doing {operation} for SQS queue {QueueName}", exc);
}View on GitHub (pinned to fca799fa70)
Solutions
- Only delete messages freshly obtained from GetMessages so ReceiptHandle is populated.
- Delete within the SQS visibility timeout before the handle becomes invalid.
- If you build SQSMessage manually, set ReceiptHandle from a valid receive operation.
- Add a guard: if (string.IsNullOrWhiteSpace(msg.ReceiptHandle)) skip and log.
Example fix
// before
var msg = new SQSMessage { Body = payload }; // no ReceiptHandle
await storage.DeleteMessage(msg); // throws
// after
var received = (await storage.GetMessages(1)).First(); // has ReceiptHandle
await storage.DeleteMessage(received); Defensive patterns
Strategy: validation
Validate before calling
if (message is null || string.IsNullOrWhiteSpace(message.ReceiptHandle))
{
logger.LogWarning("Cannot delete SQS message: missing ReceiptHandle.");
return;
}
await storage.DeleteMessage(message); Type guard
static bool HasReceiptHandle(SQSMessage m) => !string.IsNullOrWhiteSpace(m?.ReceiptHandle);
Try / catch
try { await storage.DeleteMessage(message); }
catch (ArgumentNullException ex) when (ex.ParamName == "ReceiptHandle")
{
logger.LogWarning("Delete skipped: SQS message has no ReceiptHandle.");
} Prevention
- Only delete messages you just received from GetMessages.
- Delete within the visibility timeout.
- Never build SQSMessage by hand for deletion.
When it happens
Trigger: Deleting an SQSMessage that was constructed manually without a ReceiptHandle, deleting a message whose ReceiptHandle expired, or deleting an object populated from a partial/older payload where ReceiptHandle was never set.
Common situations: Reusing a message object across the visibility-timeout boundary after the handle lapsed; deserializing a stored message without its handle; test fixtures that build SQSMessage instances by hand.
Related errors
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/5f1263f39ae63852.
Report an issue: GitHub.