maxrave-dev / maxrave-dev/SimpMusic
[BUG] [Desktop] NullPointerException on track deletion/download when restoring backup with downloadable content from Android
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 11.4k
- Forks
- 599
- Avg merge
- 3d 18h
- Merged PRs (30d)
- 7
Description
Duplicate Check
- I confirm I searched for existing reports and found no duplicates.
Describe the Bug
When restoring a backup created with the "Backup with downloadable content" feature from an Android device onto the Linux Desktop (Compose Multiplatform) client, songs are marked as "Downloaded" but fail to play offline. Attempting to click the "Downloaded" button to remove and re-download the track triggers a java.lang.NullPointerException crash in DownloadUtils.kt.
Steps to Reproduce
- Export a "Backup with downloadable content" from the Android version of Simp Music.
- Restore this backup file on the Linux Desktop client (CachyOS / Hyprland).
- Disconnect internet access and attempt to play a track marked as downloaded (playback fails).
- Connect back to the internet and click the "Downloaded" button on any restored track to remove/re-download it.
- The application crashes immediately.
Expected Behavior
The app should either map/handle invalid cross-platform storage paths gracefully without throwing a NullPointerException, or allow the user to clear/re-download tracks whose local storage paths do not exist on the current OS.
App Version
1.7.0
Android Version
Android 11 & CachyOS Linux (Hyprland)
Device Model
Samsung A20s & HP Elitebook
Custom ROM
- I am using a custom ROM
Custom ROM Name (if applicable)
No response
Screenshots (optional)
Log / Error Details
java.lang.NullPointerException: must not be null
at com.simpmusic.media_jvm.b.a.a(DownloadUtils.kt)
at com.maxrave.simpmusic.e.y$b.invokeSuspend(NowPlayingBottomSheetViewModel.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWithInternal(DispatchedContinuation.kt)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
at com.maxrave.simpmusic.e.y.a(NowPlayingBottomSheetViewModel.kt)
at com.maxrave.simpmusic.ui.a.S.a(ModalBottomSheet.kt)
at com.maxrave.simpmusic.ui.a.S.c(ModalBottomSheet.kt)
at androidx.compose.b.r.c(Clickable.kt)
at androidx.compose.b.r.a(Clickable.kt)
at androidx.compose.ui.j.d.h.a(HitPathTracker.kt)
at androidx.compose.ui.j.d.h.a(HitPathTracker.kt)
at androidx.compose.ui.j.d.h.a(HitPathTracker.kt)
at androidx.compose.ui.j.d.h.a(HitPathTracker.kt)
at androidx.compose.ui.j.d.h.a(HitPathTracker.kt)
at androidx.compose.ui.j.d.i.a(HitPathTracker.kt)
at androidx.compose.ui.j.d.e.a(HitPathTracker.kt)
at androidx.compose.ui.j.d.D.a(PointerInputEventProcessor.kt)
at androidx.compose.ui.o.aE.a(RootNodeOwner.skiko.kt)
at androidx.compose.ui.r.c.d(CanvasLayersComposeScene.skiko.kt)
at androidx.compose.ui.r.c.a(CanvasLayersComposeScene.skiko.kt)
at androidx.compose.ui.r.a.b(BaseComposeScene.skiko.kt)
at androidx.compose.ui.r.a.a(BaseComposeScene.skiko.kt)
at androidx.compose.ui.r.a$c.a(BaseComposeScene.skiko.kt)
at androidx.compose.ui.r.a$c.invoke(BaseComposeScene.skiko.kt)
at androidx.compose.ui.j.d.S.j(SyntheticEventSender.skiko.kt)
at androidx.compose.ui.j.d.S.a(SyntheticEventSender.skiko.kt)
at androidx.compose.ui.r.k.a(ComposeSceneInputHandler.skiko.kt)
at androidx.compose.ui.r.k.a(ComposeSceneInputHandler.skiko.kt)
at androidx.compose.ui.r.a.a(BaseComposeScene.skiko.kt)
at androidx.compose.ui.r.f.a(ComposeScene.skiko.kt)
at androidx.compose.ui.r.p.b(ComposeSceneMediator.desktop.kt)
at androidx.compose.ui.r.p.a(ComposeSceneMediator.desktop.kt)
at androidx.compose.ui.r.o.b(ComposeSceneMediator.desktop.kt)
at androidx.compose.ui.r.o.a(ComposeSceneMediator.desktop.kt)
at androidx.compose.ui.r.o$l.mouseReleased(ComposeSceneMediator.desktop.kt)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6621)
at java.desktop/java.awt.Component.processEvent(Component.java:6386)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4996)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4828)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:98)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@40688ce1, Dispatchers.Main.immediate]
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with DownloadUtils.kt and the NowPlayingBottomSheetViewModel.kt call shown in the stack trace, then reproduce the Android backup restoration on the Linux Desktop client. Trace the restored track's local storage path and verify that clicking Downloaded neither crashes nor leaves the track unusable; completion should allow invalid paths to be cleared or tracks to be re-downloaded.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin, linux
- Domain
- desktop, mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100