dotnet/orleans · error · ArgumentException
{nameof(AdoNetQueueAdapter)} does not support a user supplie
Error message
{nameof(AdoNetQueueAdapter)} does not support a user supplied {nameof(StreamSequenceToken)}. What it means
Thrown by AdoNetQueueAdapter.QueueMessageBatchAsync when the caller supplies a non-null StreamSequenceToken. The ADO.NET streaming provider is non-rewindable: it cannot replay from an arbitrary offset, so user-supplied tokens are unsupported and rejected upfront rather than silently ignored.
Source
Thrown at src/AdoNet/Orleans.Streaming.AdoNet/AdoNetQueueAdapter.cs:39
/// The ADO.NET provider works both ways.
/// </summary>
public StreamProviderDirection Direction => StreamProviderDirection.ReadWrite;
public IQueueAdapterReceiver CreateReceiver(QueueId queueId)
{
// map the queue id
var adoNetQueueId = mapper.GetAdoNetQueueId(queueId);
// create the receiver
return ReceiverFactory(serviceProvider, [Name, adoNetQueueId, streamOptions, clusterOptions, cacheOptions, queries]);
}
public async Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken? token, Dictionary<string, object>? requestContext)
{
// the ADO.NET provider is not rewindable so we do not support user supplied tokens
if (token is not null)
{
throw new ArgumentException($"{nameof(AdoNetQueueAdapter)} does not support a user supplied {nameof(StreamSequenceToken)}.");
}
// map the Orleans stream id to the corresponding queue id
var queueId = mapper.GetAdoNetQueueId(streamId);
// create the payload from the events
var payload = AdoNetBatchContainer.ToMessagePayload(serializer, streamId, events.Cast<object>().ToList(), requestContext);
// we can enqueue the message now
try
{
await queries.QueueStreamMessageAsync(clusterOptions.ServiceId, Name, queueId, payload, streamOptions.ExpiryTimeout.TotalSecondsCeiling());
}
catch (Exception ex)
{
LogFailedToQueueStreamMessage(ex, clusterOptions.ServiceId, Name, queueId);
throw;
}View on GitHub (pinned to fca799fa70)
Solutions
- Pass null for the StreamSequenceToken when producing to the ADO.NET adapter.
- If you need rewindability, switch to a rewindable streaming provider instead of ADO.NET.
- Audit any custom producer/adapter wrapper to ensure it forwards null tokens to ADO.NET.
Example fix
// before await adapter.QueueMessageBatchAsync(streamId, events, new EventSequenceTokenV2(5), requestContext); // after await adapter.QueueMessageBatchAsync(streamId, events, token: null, requestContext);
Defensive patterns
Strategy: type-guard
Type guard
// ADO.NET adapter is non-rewindable; only null tokens are valid. static bool IsValidTokenForAdoNet(StreamSequenceToken? token) => token is null;
Try / catch
try { await adapter.QueueMessageBatchAsync(streamId, events, token, ctx); }
catch (ArgumentException ex) when (ex.Message.Contains("does not support a user supplied"))
{
// drop the token and retry with null.
} Prevention
- Pass null as the token when producing to the ADO.NET stream adapter.
- If rewindability is required, choose a rewindable provider instead of ADO.NET.
- Audit custom adapter wrappers to forward null tokens.
When it happens
Trigger: QueueMessageBatchAsync is called with a non-null token argument. In normal Orleans usage the streaming runtime passes null for the token on a non-rewindable provider, so this fires only if custom code drives the adapter directly with a token.
Common situations: Custom producer code calling the queue adapter with a checkpoint token; porting rewindable-provider code (e.g. Azure Event Hubs) to ADO.NET without dropping the token; an IStreamQueueMapper/adapter wrapper forwarding tokens.
Related errors
- Cannot get events from a half-baked {nameof(AdoNetBatchConta
- {nameof(options.DeleteStateOnClear)}=true is not supported.
- Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Str
- Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Str
- Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Str
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/8602eb58147b05cb.
Report an issue: GitHub.