In what version(s) of Spring AMQP are you seeing this issue?

main

Describe the bug

org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainerTests#testAddQueuesAndStartInCycle can fail with a ConcurrentModificationException on shutdown. It doesn't happen every time so either the test needs to be more robust or it exposes an actual issue in SimpleMessageListenerContainer:

2025-08-22 08:22:24,015  INFO org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer [main] : Waiting for workers to finish.
2025-08-22 08:22:24,016  INFO org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer [main] : Workers not finished.
2025-08-22 08:22:24,016 ERROR org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer [not.a.Spring.bean-3] : Stopping container from aborted consumer

org.springframework.amqp.UncategorizedAmqpException: java.util.ConcurrentModificationException

    at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:81)
    at org.springframework.amqp.rabbit.connection.RabbitAccessor.convertRabbitAccessException(RabbitAccessor.java:117)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.shutdown(AbstractMessageListenerContainer.java:1345)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.shutdown(AbstractMessageListenerContainer.java:1313)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doStop(AbstractMessageListenerContainer.java:1468)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.stop(AbstractMessageListenerContainer.java:1454)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainerTests.testAddQueuesAndStartInCycle(SimpleMessageListenerContainerTests.java:417)
    at java.base/java.lang.reflect.Method.invoke(Method.java:565)
    at java.base/java.util.Optional.ifPresent(Optional.java:178)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:186)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:215)
    at java.base/java.util.stream.IntPipeline$1$1.accept(IntPipeline.java:180)
    at java.base/java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:104)
    at java.base/java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:712)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:570)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:560)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:153)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:176)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265)
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:636)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
Caused by: java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1606)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.lambda$shutdownAndWaitOrCallback$0(SimpleMessageListenerContainer.java:709)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.shutdownAndWaitOrCallback(SimpleMessageListenerContainer.java:736)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.shutdown(AbstractMessageListenerContainer.java:1342)
    ... 19 more

To Reproduce

Replace @Test by @RepeatedTest(100) and it should eventually fail.

Comment From: snicoll

this.processorThreadsToInterrupt can be updated whiile shutdownAndWaitOrCallback is looping over it. I suppose there are other areas, in particular in Spring Framework, where this happens and there's an idiomatic way of dealing with that problem.

Comment From: artembilan

Thank you, Stephane! This is new: have just pushed that new functionality yesterday . I think I know what is going on: while we are looping in the mention method, one of the processors might finish normally removing itself from that list. Just synchronization on the list should be enough to fix.

Will look into that when I’m back.

Comment From: artembilan

Regression after: https://github.com/spring-projects/spring-amqp/issues/2920