{"record":{"id":"34fcf4616522a591","repo":"dotnet/orleans","slug":"eventhub-streams-currently-does-not-support-non-nu","errorCode":null,"errorMessage":"EventHub streams currently does not support non-null StreamSequenceToken.","messagePattern":"EventHub streams currently does not support non-null StreamSequenceToken\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubDataAdapter.cs","lineNumber":58,"sourceCode":"        /// <returns></returns>\n        protected virtual IBatchContainer GetBatchContainer(EventHubMessage eventHubMessage)\n        {\n            return new EventHubBatchContainer(eventHubMessage, this.serializer);\n        }\n\n        /// <summary>\n        /// Gets the stream sequence token from a cached message.\n        /// </summary>\n        /// <param name=\"cachedMessage\"></param>\n        /// <returns></returns>\n        public virtual StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage)\n        {\n            return new EventHubSequenceTokenV2(\"\", cachedMessage.SequenceNumber, 0);\n        }\n\n        public virtual EventData ToQueueMessage<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken? token, Dictionary<string, object>? requestContext)\n        {\n            if (token != null) throw new ArgumentException(\"EventHub streams currently does not support non-null StreamSequenceToken.\", nameof(token));\n            return EventHubBatchContainer.ToEventData(this.serializer, streamId, events, requestContext);\n        }\n\n        public virtual CachedMessage FromQueueMessage(StreamPosition streamPosition, EventData queueMessage, DateTime dequeueTime, Func<int, ArraySegment<byte>> getSegment)\n        {\n            return new CachedMessage()\n            {\n                StreamId = streamPosition.StreamId,\n                SequenceNumber = queueMessage.SequenceNumber,\n                EventIndex = streamPosition.SequenceToken.EventIndex,\n                EnqueueTimeUtc = queueMessage.EnqueuedTime.UtcDateTime,\n                DequeueTimeUtc = dequeueTime,\n                Segment = EncodeMessageIntoSegment(queueMessage, getSegment)\n            };\n        }\n\n        public virtual StreamPosition GetStreamPosition(string partition, EventData queueMessage)\n        {","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubDataAdapter.cs#L40-L76","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Pass null as the StreamSequenceToken when calling OnNextAsync on an Event Hub-backed stream.","If relaying events between streams, do not forward the source token to the Event Hub producer — call stream.OnNextAsync(event) without a token.","If you need ordering semantics, rely on Event Hub's per-partition ordering and partition keys, not on the StreamSequenceToken."],"exampleFix":"// before\nawait eventHubStream.OnNextAsync(myEvent, sourceToken); // throws\n\n// after\nawait eventHubStream.OnNextAsync(myEvent); // token defaults to null\n// or explicitly:\nawait eventHubStream.OnNextAsync(myEvent, null);","handlingStrategy":"validation","validationCode":"// Before calling OnNextAsync on an Event Hub stream, ensure token is null:\nStreamSequenceToken? tokenToUse = streamProviderIsEventHub ? null : token;\nawait stream.OnNextAsync(myEvent, tokenToUse);\n\n// Or guard explicitly:\nif (token != null && isEventHubStream)\n{\n    logger.LogWarning(\"Event Hub streams do not support non-null StreamSequenceToken; ignoring token.\");\n    token = null;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass a StreamSequenceToken to OnNextAsync on an Event Hub-backed stream — always pass null.","When relaying events between streams, do not forward the source token to the Event Hub producer.","Rely on Event Hub per-partition ordering and partition keys for ordering semantics, not StreamSequenceToken."],"tags":["stream-sequence-token","eventhub","producer","validation","append-only"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}