dotnet/orleans · warning · NotSupportedException

This adapter only supports read

Error message

This adapter only supports read

What it means

Thrown by the CustomDataAdapter sample's ToQueueMessage override to make the stream adapter explicitly write-only-incompatible — the sample demonstrates a read-only Event Hubs consumer adapter and intentionally forbids producing. Any code path that tries to publish events through this provider hits the NotSupportedException by design.

Solutions

  1. Do not produce through this provider — it is a consumer-only sample. Publish through a different stream provider configured with a full bidirectional adapter.
  2. If you need bidirectional support, implement ToQueueMessage in your own adapter instead of inheriting the sample's throw.
  3. Verify which provider name a producer grain targets (Constants.StreamProvider) versus the one configured with CustomDataAdapter.

Example fix

// before: producing through the read-only sample adapter
var stream = provider.GetStream<int>(streamId);
await stream.OnNextAsync(1); // hits ToQueueMessage -> NotSupportedException

// after: publish via a provider whose adapter implements ToQueueMessage
var writeStream = writeProvider.GetStream<int>(streamId);
await writeStream.OnNextAsync(1);
Defensive patterns

Strategy: validation

Validate before calling

// Only subscribe/consume on the read-only provider; publish via a separate provider
if (providerName == "CustomDataAdapter")
    throw new InvalidOperationException("Provider is read-only; do not produce.");

Type guard

null

Try / catch

try
{
    await stream.OnNextAsync(value);
}
catch (NotSupportedException ex) when (ex.Message.Contains("only supports read"))
{
    // Route production to a bidirectional provider instead
}

Prevention

When it happens

Trigger: A grain or client calls GetStreamProvider(...).GetStream<T>(streamId).OnNextAsync(...) while the provider is configured with CustomDataAdapter, whose ToQueueMessage (the produce path) always throws.

Common situations: Reusing the read-only sample adapter in a project that also needs to publish; wiring the same adapter to a producer grain by mistake; assuming every EventDataBatchContainerAdapter supports both directions.

Related errors


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

Appendix: source

Thrown at samples/Streaming/CustomDataAdapter/Silo/CustomDataAdapter.cs:28

// Custom EventHubDataAdapter that serialize event using System.Text.Json
public class CustomDataAdapter : EventHubDataAdapter
{
    public CustomDataAdapter(Serializer serializer) : base(serializer)
    {
    }

    public override string GetPartitionKey(StreamId streamId)
        => streamId.ToString();

    public override StreamId GetStreamIdentity(EventData queueMessage)
    {
        var guid = Guid.Parse(queueMessage.PartitionKey);
        var ns = (string) queueMessage.Properties["StreamNamespace"];
        return StreamId.Create(ns, guid);
    }

    public override EventData ToQueueMessage<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken? token, Dictionary<string, object>? requestContext)
        => throw new NotSupportedException("This adapter only supports read");

    protected override IBatchContainer GetBatchContainer(EventHubMessage eventHubMessage)
        => new CustomBatchContainer(eventHubMessage);
}

[GenerateSerializer, Immutable]
public sealed class CustomBatchContainer : IBatchContainer
{
    [Id(0)]
    private readonly EventHubMessage _eventHubMessage;

    [Id(1)]
    public StreamSequenceToken SequenceToken { get; }

    public StreamId StreamId => _eventHubMessage.StreamId;

    public CustomBatchContainer(EventHubMessage eventHubMessage)
    {

View on GitHub (pinned to fca799fa70)