{"record":{"id":"1997d6dac1c58f9a","repo":"dotnet/orleans","slug":"cannot-get-events-from-a-half-baked-nameof-adonet","errorCode":null,"errorMessage":"Cannot get events from a half-baked {nameof(AdoNetBatchContainer)}","messagePattern":"Cannot get events from a half-baked (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/AdoNet/Orleans.Streaming.AdoNet/AdoNetBatchContainer.cs","lineNumber":52,"sourceCode":"    [Id(3)]\n    public EventSequenceTokenV2 SequenceToken { get; internal set; } = null!;\n\n    /// <summary>\n    /// Holds the receipt for message confirmation.\n    /// </summary>\n    [Id(4)]\n    public int Dequeued { get; internal set; }\n\n    #endregion Serialized State\n\n    #region Interface\n\n    StreamSequenceToken IBatchContainer.SequenceToken => SequenceToken;\n\n    public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n    {\n        return SequenceToken is null\n            ? throw new InvalidOperationException($\"Cannot get events from a half-baked {nameof(AdoNetBatchContainer)}\")\n            : Events\n                .OfType<T>()\n                .Select((e, i) => Tuple.Create<T, StreamSequenceToken>(e, SequenceToken.CreateSequenceTokenForEvent(i)));\n    }\n\n    public bool ImportRequestContext()\n    {\n        if (RequestContext is not null)\n        {\n            RequestContextExtensions.Import(RequestContext);\n            return true;\n        }\n\n        return false;\n    }\n\n    #endregion Interface\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/AdoNet/Orleans.Streaming.AdoNet/AdoNetBatchContainer.cs#L34-L70","documentation":"Thrown by AdoNetBatchContainer.GetEvents<T>() when SequenceToken is null. A container built via the public constructor (used for sending) has no sequence token; only containers materialized from a stored message via FromMessage get a SequenceToken assigned. Calling GetEvents on a send-side container is invalid because there is no offset to anchor the events to.","triggerScenarios":"GetEvents<T>() is invoked on an AdoNetBatchContainer whose SequenceToken was never set — i.e., one created by ToMessagePayload/new AdoNetBatchContainer rather than deserialized and stamped via FromMessage.","commonSituations":"Custom streaming code or tests that construct an AdoNetBatchContainer directly and call GetEvents; reflection/serialization round-trips that bypass FromMessage; misuse of an internal type outside its receive path.","solutions":["Only call GetEvents on containers obtained from the ADO.NET stream receiver (built via FromMessage, which sets SequenceToken).","In tests, set container.SequenceToken = new EventSequenceTokenV2(...) before calling GetEvents.","Do not reuse send-side containers (from ToMessagePayload) for event enumeration."],"exampleFix":"// before (test/misuse)\nvar container = new AdoNetBatchContainer(streamId, events, null);\nforeach (var ev in container.GetEvents<MyEvent>()) { } // SequenceToken null -> error\n\n// after\ncontainer.SequenceToken = new EventSequenceTokenV2(0);\nforeach (var ev in container.GetEvents<MyEvent>()) { }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Only enumerate events from receive-side containers (token set).\nstatic bool IsReadyForEvents(AdoNetBatchContainer c) => c.SequenceToken is not null;","tryCatchPattern":"try { foreach (var e in container.GetEvents<T>()) { /* ... */ } }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"half-baked\"))\n{\n    // container was not materialized via FromMessage; log and skip.\n}","preventionTips":["Treat AdoNetBatchContainer as receive-only for GetEvents; obtain it from the stream receiver.","In tests, always set SequenceToken before GetEvents.","Never reuse a send-side container (from ToMessagePayload) for enumeration."],"tags":["adonet","streaming","batch-container","sequence-token","runtime"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}