dotnet/orleans · error · ArgumentException

EventHub streams currently does not support non-null StreamS

Error message

EventHub streams currently does not support non-null StreamSequenceToken.

What it means

EventHubDataAdapter.ToQueueMessage throws ArgumentException when a non-null StreamSequenceToken is provided because Azure Event Hub is an append-only log — you cannot write to a specific sequence position. The token parameter is accepted for interface compatibility (IOnDemandAdaptor) but Event Hub producer writes always append to the end of the partition, making any positional token meaningless for production.

Source

Thrown at src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubDataAdapter.cs:58

        /// <returns></returns>
        protected virtual IBatchContainer GetBatchContainer(EventHubMessage eventHubMessage)
        {
            return new EventHubBatchContainer(eventHubMessage, this.serializer);
        }

        /// <summary>
        /// Gets the stream sequence token from a cached message.
        /// </summary>
        /// <param name="cachedMessage"></param>
        /// <returns></returns>
        public virtual StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage)
        {
            return new EventHubSequenceTokenV2("", cachedMessage.SequenceNumber, 0);
        }

        public virtual EventData ToQueueMessage<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken? token, Dictionary<string, object>? requestContext)
        {
            if (token != null) throw new ArgumentException("EventHub streams currently does not support non-null StreamSequenceToken.", nameof(token));
            return EventHubBatchContainer.ToEventData(this.serializer, streamId, events, requestContext);
        }

        public virtual CachedMessage FromQueueMessage(StreamPosition streamPosition, EventData queueMessage, DateTime dequeueTime, Func<int, ArraySegment<byte>> getSegment)
        {
            return new CachedMessage()
            {
                StreamId = streamPosition.StreamId,
                SequenceNumber = queueMessage.SequenceNumber,
                EventIndex = streamPosition.SequenceToken.EventIndex,
                EnqueueTimeUtc = queueMessage.EnqueuedTime.UtcDateTime,
                DequeueTimeUtc = dequeueTime,
                Segment = EncodeMessageIntoSegment(queueMessage, getSegment)
            };
        }

        public virtual StreamPosition GetStreamPosition(string partition, EventData queueMessage)
        {

View on GitHub (pinned to fca799fa70)

Solutions

  1. Pass null as the StreamSequenceToken when calling OnNextAsync on an Event Hub-backed stream.
  2. If relaying events between streams, do not forward the source token to the Event Hub producer — call stream.OnNextAsync(event) without a token.
  3. If you need ordering semantics, rely on Event Hub's per-partition ordering and partition keys, not on the StreamSequenceToken.

Example fix

// before
await eventHubStream.OnNextAsync(myEvent, sourceToken); // throws

// after
await eventHubStream.OnNextAsync(myEvent); // token defaults to null
// or explicitly:
await eventHubStream.OnNextAsync(myEvent, null);
Defensive patterns

Strategy: validation

Validate before calling

// Before calling OnNextAsync on an Event Hub stream, ensure token is null:
StreamSequenceToken? tokenToUse = streamProviderIsEventHub ? null : token;
await stream.OnNextAsync(myEvent, tokenToUse);

// Or guard explicitly:
if (token != null && isEventHubStream)
{
    logger.LogWarning("Event Hub streams do not support non-null StreamSequenceToken; ignoring token.");
    token = null;
}

Prevention

When it happens

Trigger: Calling OnNextAsync or StreamOnNextTrigger on an Event Hub-backed stream with a non-null StreamSequenceToken argument. This happens when application code calls stream.OnNextAsync(event, someToken) or when an implicit token is propagated from a previous stream subscription (e.g., in a stream-to-stream relay pipeline).

Common situations: Relaying events from one stream to another and passing the source stream's token to the Event Hub producer; a grain that incorrectly assumes OnNext supports rewind-based writes; code migrated from a different streaming provider (e.g., a custom queue adapter) that did support token-based writes; using implicit stream subscription pipelines where the token is forwarded automatically.

Related errors


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