microsoft/autogen · error · ArgumentException

Invalid queue type: {_queueType}.

Error message

Invalid queue type: {_queueType}.

What it means

ArgumentException thrown by MessageRegistryQueue.GetQueue() when the grain's _queueType is neither QueueType.DeadLetterQueue nor QueueType.EventBuffer. The queue grain is constructed per queue type and switches on that value to pick the right state bucket; any other value (including an uncast int or an out-of-range enum) is rejected.

Source

Thrown at dotnet/src/Microsoft.AutoGen/RuntimeGateway.Grpc/Services/Orleans/MessageRegistryQueue.cs:130

    }

    private async Task AddOrUpdate(string topic, CloudEvent message)
    {
        var queue = GetQueue();
        var list = queue.GetOrAdd(topic, _ => new());
        list.Add(message);
        queue.AddOrUpdate(topic, list, (_, _) => list);
        await _stateManager.WriteStateAsync().ConfigureAwait(true);
        _timestamps.Add(DateTime.UtcNow, topic);
    }

    private ConcurrentDictionary<string, List<CloudEvent>> GetQueue()
    {
        return _queueType switch
        {
            MessageRegistryGrain.QueueType.DeadLetterQueue => _state.State.DeadLetterQueue,
            MessageRegistryGrain.QueueType.EventBuffer => _state.State.EventBuffer,
            _ => throw new ArgumentException($"Invalid queue type: {_queueType}.")
        };
    }

    public async Task RemoveMessageAfterDelayAsync(string topic, CloudEvent message, int delay)
    {
        await Task.Delay(delay);
        await RemoveMessageAsync(topic, message);
        _currentSize -= message.CalculateSize();
    }
}

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Construct the queue grain only with MessageRegistryGrain.QueueType.DeadLetterQueue or .EventBuffer.
  2. If you add a new queue type, extend the switch in GetQueue() to map it to a state bucket (or throw a descriptive error naming the value).
  3. Validate the enum at construction: if (!Enum.IsDefined(typeof(QueueType), value)) throw ... with the actual value.

Example fix

// before
var queue = new MessageRegistryQueue((MessageRegistryGrain.QueueType)7, state, stateManager);

// after
var queue = new MessageRegistryQueue(MessageRegistryGrain.QueueType.DeadLetterQueue, state, stateManager);
Defensive patterns

Strategy: validation

Validate before calling

if (!Enum.IsDefined(typeof(MessageRegistryGrain.QueueType), queueType)
    || queueType == (MessageRegistryGrain.QueueType)(-1))
{
    throw new ArgumentOutOfRangeException(nameof(queueType), queueType, "QueueType must be DeadLetterQueue or EventBuffer");
}

Type guard

static bool IsKnownQueueType(MessageRegistryGrain.QueueType t) =>
    t is MessageRegistryGrain.QueueType.DeadLetterQueue
       or MessageRegistryGrain.QueueType.EventBuffer;

Try / catch

try { var queue = GetQueue(); }
catch (ArgumentException ex) when (ex.Message.Contains("Invalid queue type"))
{
    _logger.LogError("MessageRegistryQueue misconfigured with queue type {Type}.", _queueType);
    throw;
}

Prevention

When it happens

Trigger: Instantiating MessageRegistryQueue with an int cast to MessageRegistryGrain.QueueType that is not 0 or 1 (e.g. (QueueType)42); new queue kinds added to the enum without extending GetQueue's switch; deserialized grain state producing an unexpected enum value.

Common situations: Direct unit tests of the grain that pass arbitrary enum values; refactors that introduce a third queue type but forget this switch expression; enum reordering between serialized versions shifting numeric meanings.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/e8c6c418b99591d6. Report an issue: GitHub.