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.

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)

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.