In some environments, queues in a given virtual host suddenly receive the argument x-queue-type = "undefined" even though their applications never set this argument. This results in channel exceptions such as:
PRECONDITION_FAILED - inequivalent arg 'x-queue-type' for queue '<queue>' in vhost '<vhost>': received the value 'undefined' of type 'longstr' but current is none
The RabbitMQ Management UI may show the queue type as classic, while rabbitmqctl list_queues arguments reveals x-queue-type = "undefined" for some queues. This discrepancy leads to confusing behavior and queue declaration failures, especially after node restarts or definition imports or apps failures.
The issue is triggered when a virtual host metadata default_queue_type field is set to an unsupported value such as `"undefined"` or `<<"undefined">>` (both can be considered string values). Such values have likely bypassed validation due to one of the other known DQT-related bugs:
Standardize the default queue type to classic at both vhost and node level, and then normalize any existing queues that have x-queue-type = "undefined" or no type set.
Step 1: Set default queue type to classic. This ensures all future queue declarations without x-queue-type become classic queues.
rabbitmqctl update_vhost_metadata <vhost_name> --default-queue-type classic
rabbitmqadmin vhosts declare --name <vhost_name> --default-queue-type classic
# supported values: quorum, stream, classic, or a custom type module
default_queue_type = classic
This node‑wide DQT will be used by any vhost that does not override it.
Step 2: Bulk‑fix vhost DQT with rabbitmqctl eval (advanced)
rabbitmqctl eval '
lists:foreach(
fun(VHostName) ->
VHost = rabbit_vhost:lookup(VHostName),
Meta = vhost:get_metadata(VHost),
case maps:get(default_queue_type, Meta, undefined) of
undefined ->
rabbit_db_vhost:merge_metadata(VHostName, #{default_queue_type => <<"classic">>}),
io:format("Set DQT for virtual host ~p (was not set)~n", [VHostName]);
<<"undefined">> ->
rabbit_db_vhost:merge_metadata(VHostName, #{default_queue_type => <<"classic">>}),
io:format("Set DQT for virtual host ~p (was <<\"undefined\">>)~n", [VHostName]);
DQT ->
io:format("Virtual host ~p already has DQT = ~p~n", [VHostName, DQT])
end
end,
rabbit_vhost:list_names()),
ok.
'
This proactively prevents new queues in any vhost from inheriting a broken undefined default.
rabbitmqctl eval '
lists:foreach(
fun(Q) ->
QName = amqqueue:get_name(Q),
Args = amqqueue:get_arguments(Q),
case rabbit_misc:table_lookup(Args, <<"x-queue-type">>) of
undefined ->
NewArgs = rabbit_misc:set_table_value(Args, <<"x-queue-type">>, longstr, <<"classic">>),
rabbit_db_queue:update(QName, fun(Q0) -> amqqueue:set_arguments(Q0, NewArgs) end),
io:format("Set x-queue-type for ~p to <<\"classic\">> (was not set)~n", [QName]);
{longstr, <<"undefined">>} ->
NewArgs = rabbit_misc:set_table_value(Args, <<"x-queue-type">>, longstr, <<"classic">>),
rabbit_db_queue:update(QName, fun(Q0) -> amqqueue:set_arguments(Q0, NewArgs) end),
io:format("Set x-queue-type for ~p to <<\"classic\">> (was <<\"undefined\">>)~n", [QName]);
{_Type, Val} ->
io:format("Queue ~p already has x-queue-type = ~p~n", [QName, Val])
end
end,
rabbit_amqqueue:list()),
ok.
'
This makes all queues explicitly classic at the argument level so that Management UI no longer shows undefined, and future queue.declare calls that assume classic behavior will match the stored definition.