You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ConcurrentModificationException in MediaLibrarySessionImpl.getSubscribedControllers() #3056
Pixel 10 Pro Fold, Pixel 9 Pro XL, Pixel 8, Pixel 6, Galaxy S20, Galaxy S23 Ultra
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Not tested
Reproduction steps
Not able to reproduce, crash information is from Crashlytics
Expected result
No exception thrown
Actual result
Fatal Exception: java.util.ConcurrentModificationException:
at com.google.common.collect.CompactHashSet$1.checkForConcurrentModification(CompactHashSet.java:582)
at com.google.common.collect.CompactHashSet$1.next(CompactHashSet.java:556)
at com.google.common.collect.AbstractMapBasedMultimap$WrappedCollection$WrappedIterator.next(AbstractMapBasedMultimap.java:465)
at java.util.AbstractCollection.toArray(AbstractCollection.java:146)
at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:264)
at androidx.media3.session.MediaLibrarySessionImpl.getSubscribedControllers(MediaLibrarySessionImpl.java:246)
at androidx.media3.session.MediaLibraryService$MediaLibrarySession.getSubscribedControllers(MediaLibraryService.java:798)
at fm.libro.service.session.LibroMediaSession$subscribeToMediaItemsChanges$1$1.invokeSuspend(LibroMediaSession.kt:24)
at fm.libro.service.session.LibroMediaSession$subscribeToMediaItemsChanges$1$1.invoke(:12)
at fm.libro.service.session.LibroMediaSession$subscribeToMediaItemsChanges$1$1.invoke(:8)
at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit(Emitters.kt:50)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAllImpl$FlowKt__ChannelsKt(Channels.kt:33)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.access$emitAllImpl$FlowKt__ChannelsKt(Channels.kt:1)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAllImpl$1.invokeSuspend(:14)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1154)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:652)
at java.lang.Thread.run(Thread.java:1563)
If you find some time to tell us a bit about the threading model of your app in which that call is executed and producing the exception that would be great. I have some assumptions, but I think it's more efficient to get some information from the pros. It would allow me to try to reproduce exact your case and make a unit test to test the regression.
I'm aware you can't reproduce yourself. Let us know about the app architecture specifically the threading. This may help us to a) give you some ideas how you could fix that on your end without needing to wait for a fix from our end, and b) to fix this on our end to either make it thread safe or add some checks from what threads a given method is allowed to be accessed.
getSubscribedControllers() is being called from a Kotlin coroutine running on a custom IO thread pool (unbounded Executors.newCachedThreadPool()), not from the main thread.
We have a coroutine flow that monitors database changes and notifies subscribed controllers:
Activity
marcbaechinger commentedon Feb 5, 2026
Thanks for reporting!
If you find some time to tell us a bit about the threading model of your app in which that call is executed and producing the exception that would be great. I have some assumptions, but I think it's more efficient to get some information from the pros. It would allow me to try to reproduce exact your case and make a unit test to test the regression.
I'm aware you can't reproduce yourself. Let us know about the app architecture specifically the threading. This may help us to a) give you some ideas how you could fix that on your end without needing to wait for a fix from our end, and b) to fix this on our end to either make it thread safe or add some checks from what threads a given method is allowed to be accessed.
jjohnstz commentedon Feb 10, 2026
getSubscribedControllers()is being called from a Kotlin coroutine running on a custom IO thread pool (unboundedExecutors.newCachedThreadPool()), not from the main thread.We have a coroutine flow that monitors database changes and notifies subscribed controllers:
The issue
Thread A (our IO pool thread): Calls
getSubscribedControllers()→ iterates collectionThread B (Media3's thread): Controller subscribes/unsubscribes → modifies collection
Result:
ConcurrentModificationExceptionin ImmutableList.copyOf()Question
Should
getSubscribedControllers()only be called from the main thread? If yes, we can wrap it with:Or should the method be made thread-safe for calls from any thread?
marcbaechinger commentedon Feb 10, 2026
Thanks for confirming!
All methods on 'MediaSession' must be thread safe as per documentation. We have a fix for this and will update this issue when it landed in main.
Thank you for reporting and adding details, very much appreciated!
Make subscriptions for onChilldrenChanged thread safe
marcbaechinger commentedon Feb 11, 2026
The commit above should fix this.