dotnet/orleans · error · ArgumentException

SQSStream stream provider currently does not support non-nul

Error message

SQSStream stream provider currently does not support non-null StreamSequenceToken.

What it means

Thrown by SQSAdapter.QueueMessageBatchAsync when a non-null StreamSequenceToken is supplied. The SQS stream provider is non-rewindable (IsRewindable == false) and does not encode sequence tokens into SQS messages, so passing a token is rejected to prevent silent data-sequencing bugs.

Source

Thrown at src/AWS/Orleans.Streaming.SQS/Streams/SQSAdapter.cs:47

            if (string.IsNullOrEmpty(serviceId)) throw new ArgumentNullException(nameof(serviceId));
            this.loggerFactory = loggerFactory;
            this.serializer = serializer;
            DataConnectionString = dataConnectionString;
            this.ServiceId = serviceId;
            Name = providerName;
            this.streamQueueMapper = streamQueueMapper;
        }

        public IQueueAdapterReceiver CreateReceiver(QueueId queueId)
        {
            return SQSAdapterReceiver.Create(this.serializer, this.loggerFactory, queueId, DataConnectionString, this.ServiceId);
        }

        public async Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken? token, Dictionary<string, object>? requestContext)
        {
            if (token != null)
            {
                throw new ArgumentException("SQSStream stream provider currently does not support non-null StreamSequenceToken.", nameof(token));
            }
            var queueId = streamQueueMapper.GetQueueForStream(streamId);
            if (!Queues.TryGetValue(queueId, out var queue))
            {
                var tmpQueue = new SQSStorage(this.loggerFactory, queueId.ToString(), DataConnectionString, this.ServiceId);
                await tmpQueue.InitQueueAsync();
                queue = Queues.GetOrAdd(queueId, tmpQueue);
            }
            var msg = SQSBatchContainer.ToSQSMessage(this.serializer, streamId, events, requestContext);
            await queue.AddMessage(msg);
        }
    }
}

View on GitHub (pinned to fca799fa70)

Solutions

  1. Pass null for the token when producing to an SQS stream.
  2. If you need rewind/token semantics, use a provider that supports it (e.g., EventHub) instead of SQS.
  3. Audit custom observers/interceptors to ensure they do not attach tokens before the SQS adapter.
  4. Document at the call site that SQS streams are fire-and-forget / non-rewindable.

Example fix

// before
await adapter.QueueMessageBatchAsync(streamId, events, token, ctx); // token != null -> throws

// after
await adapter.QueueMessageBatchAsync(streamId, events, null, ctx);
Defensive patterns

Strategy: validation

Validate before calling

// Never pass a token to an SQS stream.
StreamSequenceToken? token = null;
await adapter.QueueMessageBatchAsync(streamId, events, token, ctx);

Try / catch

try { await adapter.QueueMessageBatchAsync(streamId, events, token, ctx); }
catch (ArgumentException ex) when (ex.Message.Contains("StreamSequenceToken"))
{
    logger.LogWarning("SQS streams ignore StreamSequenceToken; retrying with null token.");
    await adapter.QueueMessageBatchAsync(streamId, events, null, ctx);
}

Prevention

When it happens

Trigger: Calling QueueMessageBatchAsync with a token argument, or wiring the SQS provider into a pipeline that forwards tokens (e.g., a rewindable upstream or a custom observer that attaches StreamSequenceTokenV2).

Common situations: Mixing the SQS provider with rewindable semantics; porting code from EventHub/Azure Stream providers that do accept tokens; custom stream intermediaries that always forward a token.

Related errors


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