dotnetcore/CAP · error · ArgumentNullException

Value cannot be null. (Parameter 'topicNames')

Error message

Value cannot be null. (Parameter 'topicNames')

What it means

FetchTopicsAsync validates its topicNames parameter and throws ArgumentNullException when a null collection is passed. The consumer client needs at least an empty enumerable to resolve SNS topic ARNs; a null reference is treated as a programming error rather than 'no topics'.

Solutions

  1. Ensure the IEnumerable<string> passed to FetchTopicsAsync is non-null; pass Array.Empty<string>() when there are no topics
  2. Check that the configuration source feeding the topic list is populated before startup
  3. If topics are truly optional, guard with topics ?? Enumerable.Empty<string>() before calling
  4. Wrap the call in ArgumentNullException handling and fail fast with a clear log message

Example fix

// before
await consumerClient.FetchTopicsAsync(config.Topics); // config.Topics is null
// after
var topics = config.Topics ?? new List<string>();
await consumerClient.FetchTopicsAsync(topics);
Defensive patterns

Strategy: validation

Validate before calling

if (topicNames is null) throw new InvalidOperationException("topicNames must be provided (use an empty list for none)");

Type guard

bool HasTopics(IEnumerable<string>? t) => t is not null;

Try / catch

try { await client.FetchTopicsAsync(topics); } catch (ArgumentNullException ex) when (ex.ParamName == "topicNames") { logger.LogError(ex, "topicNames was null"); throw; }

Prevention

When it happens

Trigger: Calling AmazonSQSConsumerClient.FetchTopicsAsync(null) directly, or a CAP bootstrap path that passes a null topic-name collection into the SQS consumer during startup topic discovery.

Common situations: Building a custom consumer bootstrap on top of CAP where topics are read from configuration that was never populated (e.g. a missing config section deserialized to null) and the null collection is forwarded straight into FetchTopicsAsync.

Related errors


AI-assisted analysis of dotnetcore/CAP@e52b8508e5 (2026-09-14). Data as JSON: /api/errors/8b77d7e9f43b8b47. Report an issue: GitHub.

Appendix: source

Thrown at src/DotNetCore.CAP.AmazonSQS/AmazonSQSConsumerClient.cs:50

    private IAmazonSQS? _sqsClient;

    public AmazonSQSConsumerClient(string groupId, byte groupConcurrent, IOptions<AmazonSQSOptions> options)
    {
        _groupId = groupId;
        _groupConcurrent = groupConcurrent;
        _amazonSQSOptions = options.Value;
        _semaphore = new SemaphoreSlim(groupConcurrent);
    }

    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }

    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }

    public BrokerAddress BrokerAddress => new("aws_sqs", _queueUrl);

    public async Task<ICollection<string>> FetchTopicsAsync(IEnumerable<string> topicNames)
    {
        if (topicNames == null) throw new ArgumentNullException(nameof(topicNames));

        await ConnectAsync(true, false).ConfigureAwait(false);

        var topicArns = new List<string>();
        foreach (var topic in topicNames)
        {
            var createTopicRequest = new CreateTopicRequest(topic.NormalizeForAws());

            var createTopicResponse = await _snsClient!.CreateTopicAsync(createTopicRequest).ConfigureAwait(false);

            topicArns.Add(createTopicResponse.TopicArn);
        }

        await GenerateSqsAccessPolicyAsync(topicArns).ConfigureAwait(false);

        return topicArns;
    }

View on GitHub (pinned to e52b8508e5)