-
Notifications
You must be signed in to change notification settings - Fork 550
Description
Describe the bug
A java.lang.NullPointerException occurs within the flutter_downloader plugin's native Android DownloadWorker when attempting to enqueue a new download for a file that was previously downloaded, then manually deleted from storage (outside the app), and subsequently had its task record removed using FlutterDownloader.remove(taskId, shouldDeleteContent: true).
This suggests that FlutterDownloader.remove(shouldDeleteContent: true) fails to fully clear the internal state (likely within the underlying Android Download Manager) when the content it's supposed to delete is already missing. This leaves a corrupted or incomplete state, causing subsequent enqueue operations targeting the same file path to crash with a NullPointerException.
To Reproduce
Steps to reproduce the behavior:
Initial Download: Download a file successfully using FlutterDownloader.enqueue(). The file is now present on the device.
Manual File Deletion: Manually delete the physical downloaded file from the device's storage (e.g., using a file manager app). The file is now missing, but your app's internal database still has a record of it.
App-side Record Deletion (of the missing file): In the Flutter app, navigate to the list where downloaded files are displayed. The app will detect that the file is missing for this entry. When prompted (e.g., via a dialog asking to delete or re-download), choose the option to "delete the record" from the app's list. This action internally calls FlutterDownloader.remove(taskId: <original_task_id>, shouldDeleteContent: true).
Attempt Re-download (of the same file): Go to the app's main download list (where new downloads are initiated). Find the same file that was just deleted from the downloaded list. Tap the download button to initiate a new download for it using FlutterDownloader.enqueue().
See error: The download fails, and a java.lang.NullPointerException is observed in the native logs.
Expected behavior
The FlutterDownloader.enqueue() call should successfully start a new download for the file, treating the target path as available, even if a previous task for that path was removed after its content went missing. The NullPointerException should not occur.
Screenshots
N/A
Device information:
✓] Flutter (Channel stable, 3.32.8, on macOS 15.5 24F74 darwin-x64, locale en-GB) [1,475ms]
• Flutter version 3.32.8 on channel stable at /Users/aungmyooo/Development/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision edada7c56e (6 days ago), 2025-07-25 14:08:03 +0000
• Engine revision ef0cd00091
• Dart version 3.8.1
• DevTools version 2.45.1
[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [8.2s]
• Android SDK at /Users/aungmyooo/Library/Android/sdk
• Platform android-36, build-tools 36.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: flutter config --jdk-dir="path/to/jdk".
• Java version OpenJDK Runtime Environment (build 21.0.5+-13047016-b750.29)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 16.4) [3.1s]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 16F6
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [33ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2024.3) [32ms]
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 21.0.5+-13047016-b750.29)
[✓] VS Code (version 1.102.3) [27ms]
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.114.0
[✓] Connected device (4 available) [16.5s]
• SM N975F (mobile) • RF8M82Y3K9A • android-arm64 • Android 12 (API 31)
• Aung Myo’s iPhone (wireless) (mobile) • 00008120-0006612E0198A01E • ios • iOS 18.4.1 22E252
• macOS (desktop) • macos • darwin-x64 • macOS 15.5 24F74 darwin-x64
• Chrome (web) • chrome • web-javascript • Google Chrome 138.0.7204.183
[✓] Network resources [1,342ms]
• All expected network resources are available.
• No issues found!
Additional context
The issue does not occur if:
The file exists when FlutterDownloader.remove(shouldDeleteContent: true) is called (i.e., the remove operation successfully deletes the file). In this case, a subsequent enqueue for the same file path works correctly.
A new, unique filename (e.g., by appending a timestamp) is used for the subsequent enqueue operation, even if the original file was missing and its task removed. This workaround bypasses the issue by forcing flutter_downloader to treat each download as truly distinct, avoiding interaction with the corrupted internal state linked to the old, specific file path.