dotnet/orleans · error · ArgumentNullException

message

Error message

message

What it means

Thrown by SQSStorage.DeleteMessage when the supplied SQSMessage is null. The provider needs a non-null message because it reads ReceiptHandle and queues the deletion against queueUrl; a null reference would otherwise produce a NullReferenceException deeper in the call.

Source

Thrown at src/AWS/Orleans.Streaming.SQS/Storage/SQSStorage.cs:216

            }
            catch (Exception exc)
            {
                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)
        {

View on GitHub (pinned to fca799fa70)

Solutions

  1. Null-check before deleting: if (message is null) return; or skip.
  2. Ensure the upstream dequeue/GetMessages actually returned a message before attempting deletion.
  3. Guard at the adapter boundary so null never reaches DeleteMessage.
  4. Add a unit test asserting DeleteMessage rejects null cleanly.

Example fix

// before
await storage.DeleteMessage(null); // throws

// after
if (message is not null)
    await storage.DeleteMessage(message);
Defensive patterns

Strategy: type-guard

Validate before calling

if (message is null) { logger.LogDebug("DeleteMessage skipped: null message."); return; }
await storage.DeleteMessage(message);

Type guard

static bool IsDeletable(SQSMessage? m) => m is not null;

Try / catch

try { await storage.DeleteMessage(message); }
catch (ArgumentNullException ex) when (ex.ParamName == "message")
{
    logger.LogDebug("Ignored null message in DeleteMessage.");
}

Prevention

When it happens

Trigger: Passing a null SQSMessage to DeleteMessage, e.g., deleting the result of a lookup that returned null, or forwarding a null from a dequeue that yielded no message.

Common situations: Message-handling loops that call DeleteMessage on a possibly-empty peek result; adapters that lose a message reference during error paths; tests that pass null by mistake.

Related errors


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/2e826b07dda7799d. Report an issue: GitHub.