Skip to content

Fix: Prevent individual track failures from aborting entire playlist/album downloads#814

Merged
nathom merged 2 commits intonathom:devfrom
kyrregjerstad:fix/multiple-files-error-handling
Mar 10, 2025
Merged

Fix: Prevent individual track failures from aborting entire playlist/album downloads#814
nathom merged 2 commits intonathom:devfrom
kyrregjerstad:fix/multiple-files-error-handling

Conversation

@kyrregjerstad
Copy link
Copy Markdown
Contributor

@kyrregjerstad kyrregjerstad commented Mar 8, 2025

Problem

When downloading playlists or albums, a single failing track (often resulting in a JSONDecodeError) would cause the entire download process to fail, preventing users from getting any content at all.

Solution

  • Added error handling to catch exceptions during individual track downloads in playlists and albums
  • Implemented asyncio.gather(return_exceptions=True) to prevent exceptions from stopping concurrent downloads
  • Added error logging to help diagnose specific track failures

Testing

  • Created unit tests that verify error resilience in:
    • Playlist downloads
    • Album downloads
    • Main download coordination

Impact

Users can now successfully download as much content as possible from playlists and albums, even when individual tracks fail. Instead of getting nothing when a single track fails, they'll get all the working tracks with only problematic ones being skipped.

Closes #812

- Add exception handling and logging for track and media item downloads
- Capture and log errors during album, playlist, and media ripping
- Provide summary of failed items when download process completes
@nathom
Copy link
Copy Markdown
Owner

nathom commented Mar 9, 2025

I thought this behavior was already handled here:

except Exception as e:
logger.error(
f"Error downloading track '{self.meta.title}', retrying: {e}"
)
retry = True

Can you give an example of how this fails?

@kyrregjerstad
Copy link
Copy Markdown
Contributor Author

I thought this behavior was already handled here:

except Exception as e:
logger.error(
f"Error downloading track '{self.meta.title}', retrying: {e}"
)
retry = True

Can you give an example of how this fails?

You're right that there's error handling for track downloads in track.py, but the issue occurs at a higher level in the execution flow.

I was encountering this specific error that would abort entire playlist downloads:

JSONDecodeError: Expecting value: line 1 column 1 (char 0)
...
<sys>:0: RuntimeWarning: coroutine 'Playlist.download.<locals>._resolve_download' was never awaited

The key problem is:

  1. asyncio.gather() is used without return_exceptions=True

  2. The error happens when parsing JSON responses during API requests:

    • When a track in a playlist has an issue, PendingPlaylistTrack.resolve() calls client.get_metadata()
    • This eventually calls await response.json() in the client implementation
    • If the API returns a non-JSON response, the unhandled JSONDecodeError bubbles up
    • This aborts the entire asyncio.gather() operation, leaving other downloads unfinished

The PR fixes this by adding return_exceptions=True to the asyncio.gather() calls and properly handling these exceptions, allowing the rest of the tracks to download even when one fails.

@nathom
Copy link
Copy Markdown
Owner

nathom commented Mar 10, 2025

Oh, I see metadata errors aren't handled. Good catch!

@nathom nathom merged commit 7697ae7 into nathom:dev Mar 10, 2025
@kyrregjerstad kyrregjerstad deleted the fix/multiple-files-error-handling branch March 10, 2025 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] 'Playlist.download.<locals>._resolve_download' was never awaited

2 participants