[GH-ISSUE #459] json parse error when getting playlist with no image #153

Closed
opened 2026-02-27 20:23:25 +03:00 by kerem · 20 comments
Owner

Originally created by @aome510 on GitHub (Feb 24, 2024).
Original GitHub issue: https://github.com/ramsayleung/rspotify/issues/459

Describe the bug
Calling get-playlist API with playlist having no image will return a response with images field null. However, according to https://docs.rs/rspotify-model/0.12.0/rspotify_model/playlist/struct.FullPlaylist.html, rspotify specifies the field as Vec<Image>. This leads to the following error when parsing the json response:

json parse error: invalid type: null, expected a sequence at line 1 column 293: invalid type: null, expected a sequence at line 1 column 293

To Reproduce
Steps to reproduce the behavior:

  1. Create a new playlist with Spotify, making sure that it has no image
  2. Call get-playlist API using the new playlist's URI
  3. Observe images field has a value of null
Originally created by @aome510 on GitHub (Feb 24, 2024). Original GitHub issue: https://github.com/ramsayleung/rspotify/issues/459 **Describe the bug** Calling `get-playlist` API with playlist having no image will return a response with `images` field `null`. However, according to https://docs.rs/rspotify-model/0.12.0/rspotify_model/playlist/struct.FullPlaylist.html, `rspotify` specifies the field as `Vec<Image>`. This leads to the following error when parsing the json response: ``` json parse error: invalid type: null, expected a sequence at line 1 column 293: invalid type: null, expected a sequence at line 1 column 293 ``` **To Reproduce** Steps to reproduce the behavior: 1. Create a new playlist with Spotify, making sure that it has no image 2. Call `get-playlist` API using the new playlist's URI 3. Observe `images` field has a value of `null`
kerem 2026-02-27 20:23:25 +03:00
Author
Owner

@ramsayleung commented on GitHub (Feb 27, 2024):

I was unable to reproduce this problem:

#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))]
async fn test_playlist_with_no_image() {
    let playlist_id = PlaylistId::from_id("7G9P6fNlHvQ8lkObO5MJ7O").unwrap();
    let playlist = creds_client()
        .await
        .playlist(playlist_id, None, None)
        .await
        .unwrap();
    println!("playlist: {:?}", playlist);
    assert_eq!(playlist.images.len(), 0)
}

The images field from the response is empty rather than has a value of null:

playlist: FullPlaylist { collaborative: false, description: Some(""), external_urls: {"spotify": "https://open.spotify.com/playlist/7G9P6fNlHvQ8lkObO5MJ7O"}, followers: Followers { total: 0 }, href: "https://api.spotify.com/v1/playlists/7G9P6fNlHvQ8lkObO5MJ7O", id: PlaylistId("7G9P6fNlHvQ8lkObO5MJ7O"), images: [], name: "A New Playlist", owner: PublicUser { display_name: Some("Samray Leung"), external_urls: {"spotify": "https://open.spotify.com/user/2257tjys2e2u2ygfke42niy2q"}, followers: None, href: "https://api.spotify.com/v1/users/2257tjys2e2u2ygfke42niy2q", id: UserId("2257tjys2e2u2ygfke42niy2q"), images: [] }, public: Some(false), snapshot_id: "Miw2MmI2NzNkZjBlMjJjZTU0M2UzODg4NjcxZDQzZTBmZTljYWM1YTc1", tracks: Page { href: "https://api.spotify.com/v1/playlists/7G9P6fNlHvQ8lkObO5MJ7O/tracks?offset=0&limit=100", items: [], limit: 100, next: None, offset: 0, previous: None, total: 0 } }
<!-- gh-comment-id:1965874966 --> @ramsayleung commented on GitHub (Feb 27, 2024): I was unable to reproduce this problem: ```rust #[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] async fn test_playlist_with_no_image() { let playlist_id = PlaylistId::from_id("7G9P6fNlHvQ8lkObO5MJ7O").unwrap(); let playlist = creds_client() .await .playlist(playlist_id, None, None) .await .unwrap(); println!("playlist: {:?}", playlist); assert_eq!(playlist.images.len(), 0) } ``` The `images` field from the response is empty rather than has a value of `null`: ```rust playlist: FullPlaylist { collaborative: false, description: Some(""), external_urls: {"spotify": "https://open.spotify.com/playlist/7G9P6fNlHvQ8lkObO5MJ7O"}, followers: Followers { total: 0 }, href: "https://api.spotify.com/v1/playlists/7G9P6fNlHvQ8lkObO5MJ7O", id: PlaylistId("7G9P6fNlHvQ8lkObO5MJ7O"), images: [], name: "A New Playlist", owner: PublicUser { display_name: Some("Samray Leung"), external_urls: {"spotify": "https://open.spotify.com/user/2257tjys2e2u2ygfke42niy2q"}, followers: None, href: "https://api.spotify.com/v1/users/2257tjys2e2u2ygfke42niy2q", id: UserId("2257tjys2e2u2ygfke42niy2q"), images: [] }, public: Some(false), snapshot_id: "Miw2MmI2NzNkZjBlMjJjZTU0M2UzODg4NjcxZDQzZTBmZTljYWM1YTc1", tracks: Page { href: "https://api.spotify.com/v1/playlists/7G9P6fNlHvQ8lkObO5MJ7O/tracks?offset=0&limit=100", items: [], limit: 100, next: None, offset: 0, previous: None, total: 0 } } ```
Author
Owner

@aome510 commented on GitHub (Feb 29, 2024):

I was unable to reproduce this problem:

#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))]
async fn test_playlist_with_no_image() {
    let playlist_id = PlaylistId::from_id("7G9P6fNlHvQ8lkObO5MJ7O").unwrap();
    let playlist = creds_client()
        .await
        .playlist(playlist_id, None, None)
        .await
        .unwrap();
    println!("playlist: {:?}", playlist);
    assert_eq!(playlist.images.len(), 0)
}

The images field from the response is empty rather than has a value of null:

playlist: FullPlaylist { collaborative: false, description: Some(""), external_urls: {"spotify": "https://open.spotify.com/playlist/7G9P6fNlHvQ8lkObO5MJ7O"}, followers: Followers { total: 0 }, href: "https://api.spotify.com/v1/playlists/7G9P6fNlHvQ8lkObO5MJ7O", id: PlaylistId("7G9P6fNlHvQ8lkObO5MJ7O"), images: [], name: "A New Playlist", owner: PublicUser { display_name: Some("Samray Leung"), external_urls: {"spotify": "https://open.spotify.com/user/2257tjys2e2u2ygfke42niy2q"}, followers: None, href: "https://api.spotify.com/v1/users/2257tjys2e2u2ygfke42niy2q", id: UserId("2257tjys2e2u2ygfke42niy2q"), images: [] }, public: Some(false), snapshot_id: "Miw2MmI2NzNkZjBlMjJjZTU0M2UzODg4NjcxZDQzZTBmZTljYWM1YTc1", tracks: Page { href: "https://api.spotify.com/v1/playlists/7G9P6fNlHvQ8lkObO5MJ7O/tracks?offset=0&limit=100", items: [], limit: 100, next: None, offset: 0, previous: None, total: 0 } }

Pretty weird. My playlist is public, you can try mine instead. The id is 2gaCJBCZ1h90ZdIjNV6SWw.

> curl --request GET \
          --url https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw \
          --header 'Authorization: Bearer $TOKEN' | jq

{
  "collaborative": false,
  "description": "just a test playlist",
  "external_urls": {
    "spotify": "https://open.spotify.com/playlist/2gaCJBCZ1h90ZdIjNV6SWw"
  },
  "followers": {
    "href": null,
    "total": 0
  },
  "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw",
  "id": "2gaCJBCZ1h90ZdIjNV6SWw",
  "images": null,
  "name": "new playlist",
  "owner": {
    "display_name": "Thang Pham",
    "external_urls": {
      "spotify": "https://open.spotify.com/user/31bewedqaetpovv3yqnw44jtphsy"
    },
    "href": "https://api.spotify.com/v1/users/31bewedqaetpovv3yqnw44jtphsy",
    "id": "31bewedqaetpovv3yqnw44jtphsy",
    "type": "user",
    "uri": "spotify:user:31bewedqaetpovv3yqnw44jtphsy"
  },
  "primary_color": null,
  "public": true,
  "snapshot_id": "MiwxOGE5NGQ5NmU1MmNiYjdiNjYxOGU4ZDQzNjhlOTQ3YjQ3NTA3ZGMy",
  "tracks": {
    "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw/tracks?offset=0&limit=0",
    "items": [],
    "limit": 0,
    "next": null,
    "offset": 0,
    "previous": null,
    "total": 0
  },
  "type": "playlist",
  "uri": "spotify:playlist:2gaCJBCZ1h90ZdIjNV6SWw"
}
<!-- gh-comment-id:1970345070 --> @aome510 commented on GitHub (Feb 29, 2024): > I was unable to reproduce this problem: > > ```rust > #[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] > async fn test_playlist_with_no_image() { > let playlist_id = PlaylistId::from_id("7G9P6fNlHvQ8lkObO5MJ7O").unwrap(); > let playlist = creds_client() > .await > .playlist(playlist_id, None, None) > .await > .unwrap(); > println!("playlist: {:?}", playlist); > assert_eq!(playlist.images.len(), 0) > } > ``` > > The `images` field from the response is empty rather than has a value of `null`: > > ```rust > playlist: FullPlaylist { collaborative: false, description: Some(""), external_urls: {"spotify": "https://open.spotify.com/playlist/7G9P6fNlHvQ8lkObO5MJ7O"}, followers: Followers { total: 0 }, href: "https://api.spotify.com/v1/playlists/7G9P6fNlHvQ8lkObO5MJ7O", id: PlaylistId("7G9P6fNlHvQ8lkObO5MJ7O"), images: [], name: "A New Playlist", owner: PublicUser { display_name: Some("Samray Leung"), external_urls: {"spotify": "https://open.spotify.com/user/2257tjys2e2u2ygfke42niy2q"}, followers: None, href: "https://api.spotify.com/v1/users/2257tjys2e2u2ygfke42niy2q", id: UserId("2257tjys2e2u2ygfke42niy2q"), images: [] }, public: Some(false), snapshot_id: "Miw2MmI2NzNkZjBlMjJjZTU0M2UzODg4NjcxZDQzZTBmZTljYWM1YTc1", tracks: Page { href: "https://api.spotify.com/v1/playlists/7G9P6fNlHvQ8lkObO5MJ7O/tracks?offset=0&limit=100", items: [], limit: 100, next: None, offset: 0, previous: None, total: 0 } } > ``` Pretty weird. My playlist is public, you can try mine instead. The id is `2gaCJBCZ1h90ZdIjNV6SWw`. ``` > curl --request GET \ --url https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw \ --header 'Authorization: Bearer $TOKEN' | jq { "collaborative": false, "description": "just a test playlist", "external_urls": { "spotify": "https://open.spotify.com/playlist/2gaCJBCZ1h90ZdIjNV6SWw" }, "followers": { "href": null, "total": 0 }, "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw", "id": "2gaCJBCZ1h90ZdIjNV6SWw", "images": null, "name": "new playlist", "owner": { "display_name": "Thang Pham", "external_urls": { "spotify": "https://open.spotify.com/user/31bewedqaetpovv3yqnw44jtphsy" }, "href": "https://api.spotify.com/v1/users/31bewedqaetpovv3yqnw44jtphsy", "id": "31bewedqaetpovv3yqnw44jtphsy", "type": "user", "uri": "spotify:user:31bewedqaetpovv3yqnw44jtphsy" }, "primary_color": null, "public": true, "snapshot_id": "MiwxOGE5NGQ5NmU1MmNiYjdiNjYxOGU4ZDQzNjhlOTQ3YjQ3NTA3ZGMy", "tracks": { "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw/tracks?offset=0&limit=0", "items": [], "limit": 0, "next": null, "offset": 0, "previous": null, "total": 0 }, "type": "playlist", "uri": "spotify:playlist:2gaCJBCZ1h90ZdIjNV6SWw" } ```
Author
Owner

@ramsayleung commented on GitHub (Feb 29, 2024):

Could you provide the code snippet you were using when you encountered this error?

<!-- gh-comment-id:1970541855 --> @ramsayleung commented on GitHub (Feb 29, 2024): Could you provide the code snippet you were using when you encountered this error?
Author
Owner

@aome510 commented on GitHub (Feb 29, 2024):

Not sure what you mean by code snippet. I encountered this error when testing https://github.com/aome510/spotify-player/pull/379. After creating new playlist with create-playlist API, I couldn't enter the playlist page because the client fails to retrieve new playlist's data.

<!-- gh-comment-id:1971198080 --> @aome510 commented on GitHub (Feb 29, 2024): Not sure what you mean by code snippet. I encountered this error when testing https://github.com/aome510/spotify-player/pull/379. After creating new playlist with `create-playlist` API, I couldn't enter the playlist page because the client fails to retrieve new playlist's data.
Author
Owner

@ramsayleung commented on GitHub (Mar 1, 2024):

Even though I change the test playlist id to yours, I'm still unable to reproduce this error, the images field is deserialized as an empty vector, rather than throwing an error:

#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))]
async fn test_playlist_with_no_image() {
    let playlist_id = PlaylistId::from_id("2gaCJBCZ1h90ZdIjNV6SWw").unwrap();
    let playlist = creds_client()
        .await
        .playlist(playlist_id, None, None)
        .await
        .unwrap();
    println!("playlist: {:?}", playlist);
    assert_eq!(playlist.images.len(), 0)
}

...
playlist: FullPlaylist { collaborative: false, description: Some("just a test playlist"), external_urls: {"spotify": "https://open.spotify.com/playlist/2gaCJBCZ1h90ZdIjNV6SWw"}, followers: Followers { total: 0 }, href: "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw", id: PlaylistId("2gaCJBCZ1h90ZdIjNV6SWw"), images: [], name: "new playlist", owner: PublicUser { display_name: Some("Thang Pham"), external_urls: {"spotify": "https://open.spotify.com/user/31bewedqaetpovv3yqnw44jtphsy"}, followers: None, href: "https://api.spotify.com/v1/users/31bewedqaetpovv3yqnw44jtphsy", id: UserId("31bewedqaetpovv3yqnw44jtphsy"), images: [] }, public: Some(false), snapshot_id: "MiwxOGE5NGQ5NmU1MmNiYjdiNjYxOGU4ZDQzNjhlOTQ3YjQ3NTA3ZGMy", tracks: Page { href: "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw/tracks?offset=0&limit=100", items: [], limit: 100, next: None, offset: 0, previous: None, total: 0 } }

test test_playlist_with_no_image ... ok
...
<!-- gh-comment-id:1972342081 --> @ramsayleung commented on GitHub (Mar 1, 2024): Even though I change the test playlist id to yours, I'm still unable to reproduce this error, the `images` field is deserialized as an empty vector, rather than throwing an error: ```rust #[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] async fn test_playlist_with_no_image() { let playlist_id = PlaylistId::from_id("2gaCJBCZ1h90ZdIjNV6SWw").unwrap(); let playlist = creds_client() .await .playlist(playlist_id, None, None) .await .unwrap(); println!("playlist: {:?}", playlist); assert_eq!(playlist.images.len(), 0) } ``` ``` ... playlist: FullPlaylist { collaborative: false, description: Some("just a test playlist"), external_urls: {"spotify": "https://open.spotify.com/playlist/2gaCJBCZ1h90ZdIjNV6SWw"}, followers: Followers { total: 0 }, href: "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw", id: PlaylistId("2gaCJBCZ1h90ZdIjNV6SWw"), images: [], name: "new playlist", owner: PublicUser { display_name: Some("Thang Pham"), external_urls: {"spotify": "https://open.spotify.com/user/31bewedqaetpovv3yqnw44jtphsy"}, followers: None, href: "https://api.spotify.com/v1/users/31bewedqaetpovv3yqnw44jtphsy", id: UserId("31bewedqaetpovv3yqnw44jtphsy"), images: [] }, public: Some(false), snapshot_id: "MiwxOGE5NGQ5NmU1MmNiYjdiNjYxOGU4ZDQzNjhlOTQ3YjQ3NTA3ZGMy", tracks: Page { href: "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw/tracks?offset=0&limit=100", items: [], limit: 100, next: None, offset: 0, previous: None, total: 0 } } test test_playlist_with_no_image ... ok ... ```
Author
Owner

@aome510 commented on GitHub (Mar 1, 2024):

hmmm, interesting. Maybe the result is user-specific 🤔 .That said, it's not a breaking change to add #serde(default) for images field of FullPlaylist and SimplifiedPlaylist right?

<!-- gh-comment-id:1972418338 --> @aome510 commented on GitHub (Mar 1, 2024): hmmm, interesting. Maybe the result is user-specific 🤔 .That said, it's not a breaking change to add `#serde(default)` for `images` field of `FullPlaylist` and `SimplifiedPlaylist` right?
Author
Owner

@ramsayleung commented on GitHub (Mar 1, 2024):

#[serde(default)] is not considered a breaking change, then, what's the point of this?

<!-- gh-comment-id:1972489509 --> @ramsayleung commented on GitHub (Mar 1, 2024): `#[serde(default)]` is not considered a breaking change, then, what's the point of this?
Author
Owner

@aome510 commented on GitHub (Mar 1, 2024):

It will help to not throw an error when parsing playlist with null images field

<!-- gh-comment-id:1973220724 --> @aome510 commented on GitHub (Mar 1, 2024): It will help to not throw an error when parsing playlist with null `images` field
Author
Owner

@BeauCranston commented on GitHub (Mar 22, 2024):

Hello, I just encountered an error similar to this and my problem was that I had a playlist that was empty however I am on version 0.10 since I am using spotify-tui so this may be irrelevant but thought I would leave this here just in case.

As soon as I added a song to my empty playlist everything worked fine.

<!-- gh-comment-id:2015490244 --> @BeauCranston commented on GitHub (Mar 22, 2024): Hello, I just encountered an error similar to this and my problem was that I had a playlist that was empty however I am on version 0.10 since I am using spotify-tui so this may be irrelevant but thought I would leave this here just in case. As soon as I added a song to my empty playlist everything worked fine.
Author
Owner

@trumank commented on GitHub (Mar 28, 2024):

It seems Spotify is returning different responses (the image field specifically) depending on the account/bearer token used.

Using rspotify's test account bearer:

{
  "collaborative": false,
  "description": "just a test playlist",
  "external_urls": {
    "spotify": "https://open.spotify.com/playlist/2gaCJBCZ1h90ZdIjNV6SWw"
  },
  "followers": {
    "href": null,
    "total": 0
  },
  "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw",
  "id": "2gaCJBCZ1h90ZdIjNV6SWw",
  "images": [],
  "name": "new playlist",
  "owner": {
    "display_name": "Thang Pham",
    "external_urls": {
      "spotify": "https://open.spotify.com/user/31bewedqaetpovv3yqnw44jtphsy"
    },
    "href": "https://api.spotify.com/v1/users/31bewedqaetpovv3yqnw44jtphsy",
    "id": "31bewedqaetpovv3yqnw44jtphsy",
    "type": "user",
    "uri": "spotify:user:31bewedqaetpovv3yqnw44jtphsy"
  },
  "primary_color": null,
  "public": false,
  "snapshot_id": "MiwxOGE5NGQ5NmU1MmNiYjdiNjYxOGU4ZDQzNjhlOTQ3YjQ3NTA3ZGMy",
  "tracks": {
    "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw/tracks?offset=0&limit=100",
    "items": [],
    "limit": 100,
    "next": null,
    "offset": 0,
    "previous": null,
    "total": 0
  },
  "type": "playlist",
  "uri": "spotify:playlist:2gaCJBCZ1h90ZdIjNV6SWw"
}

Using the bearer token for my personal account obtained from ncspot's log:

{
  "collaborative": false,
  "description": "just a test playlist",
  "external_urls": {
    "spotify": "https://open.spotify.com/playlist/2gaCJBCZ1h90ZdIjNV6SWw"
  },
  "followers": {
    "href": null,
    "total": 0
  },
  "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw",
  "id": "2gaCJBCZ1h90ZdIjNV6SWw",
  "images": null,
  "name": "new playlist",
  "owner": {
    "display_name": "Thang Pham",
    "external_urls": {
      "spotify": "https://open.spotify.com/user/31bewedqaetpovv3yqnw44jtphsy"
    },
    "href": "https://api.spotify.com/v1/users/31bewedqaetpovv3yqnw44jtphsy",
    "id": "31bewedqaetpovv3yqnw44jtphsy",
    "type": "user",
    "uri": "spotify:user:31bewedqaetpovv3yqnw44jtphsy"
  },
  "primary_color": null,
  "public": true,
  "snapshot_id": "MiwxOGE5NGQ5NmU1MmNiYjdiNjYxOGU4ZDQzNjhlOTQ3YjQ3NTA3ZGMy",
  "tracks": {
    "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw/tracks?offset=0&limit=0",
    "items": [],
    "limit": 0,
    "next": null,
    "offset": 0,
    "previous": null,
    "total": 0
  },
  "type": "playlist",
  "uri": "spotify:playlist:2gaCJBCZ1h90ZdIjNV6SWw"
}
<!-- gh-comment-id:2025109275 --> @trumank commented on GitHub (Mar 28, 2024): It seems Spotify is returning different responses (the `image` field specifically) depending on the account/bearer token used. Using rspotify's test account bearer: ```json { "collaborative": false, "description": "just a test playlist", "external_urls": { "spotify": "https://open.spotify.com/playlist/2gaCJBCZ1h90ZdIjNV6SWw" }, "followers": { "href": null, "total": 0 }, "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw", "id": "2gaCJBCZ1h90ZdIjNV6SWw", "images": [], "name": "new playlist", "owner": { "display_name": "Thang Pham", "external_urls": { "spotify": "https://open.spotify.com/user/31bewedqaetpovv3yqnw44jtphsy" }, "href": "https://api.spotify.com/v1/users/31bewedqaetpovv3yqnw44jtphsy", "id": "31bewedqaetpovv3yqnw44jtphsy", "type": "user", "uri": "spotify:user:31bewedqaetpovv3yqnw44jtphsy" }, "primary_color": null, "public": false, "snapshot_id": "MiwxOGE5NGQ5NmU1MmNiYjdiNjYxOGU4ZDQzNjhlOTQ3YjQ3NTA3ZGMy", "tracks": { "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw/tracks?offset=0&limit=100", "items": [], "limit": 100, "next": null, "offset": 0, "previous": null, "total": 0 }, "type": "playlist", "uri": "spotify:playlist:2gaCJBCZ1h90ZdIjNV6SWw" } ``` Using the bearer token for my personal account obtained from ncspot's log: ```json { "collaborative": false, "description": "just a test playlist", "external_urls": { "spotify": "https://open.spotify.com/playlist/2gaCJBCZ1h90ZdIjNV6SWw" }, "followers": { "href": null, "total": 0 }, "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw", "id": "2gaCJBCZ1h90ZdIjNV6SWw", "images": null, "name": "new playlist", "owner": { "display_name": "Thang Pham", "external_urls": { "spotify": "https://open.spotify.com/user/31bewedqaetpovv3yqnw44jtphsy" }, "href": "https://api.spotify.com/v1/users/31bewedqaetpovv3yqnw44jtphsy", "id": "31bewedqaetpovv3yqnw44jtphsy", "type": "user", "uri": "spotify:user:31bewedqaetpovv3yqnw44jtphsy" }, "primary_color": null, "public": true, "snapshot_id": "MiwxOGE5NGQ5NmU1MmNiYjdiNjYxOGU4ZDQzNjhlOTQ3YjQ3NTA3ZGMy", "tracks": { "href": "https://api.spotify.com/v1/playlists/2gaCJBCZ1h90ZdIjNV6SWw/tracks?offset=0&limit=0", "items": [], "limit": 0, "next": null, "offset": 0, "previous": null, "total": 0 }, "type": "playlist", "uri": "spotify:playlist:2gaCJBCZ1h90ZdIjNV6SWw" } ```
Author
Owner

@trumank commented on GitHub (Mar 28, 2024):

And this patch allows playlists to load for me in ncspot:

diff --git a/rspotify-model/src/playlist.rs b/rspotify-model/src/playlist.rs
index 07bb7b2..776f1e2 100644
--- a/rspotify-model/src/playlist.rs
+++ b/rspotify-model/src/playlist.rs
@@ -5,10 +5,18 @@ use serde::{Deserialize, Serialize};

 use std::collections::HashMap;

 use crate::{Followers, Image, Page, PlayableItem, PlaylistId, PublicUser};

+fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+where
+    T: Default + serde::Deserialize<'de>,
+    D: serde::Deserializer<'de>,
+{
+    Ok(Option::deserialize(deserializer)?.unwrap_or_default())
+}
+
 /// Playlist result object
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
 pub struct PlaylistResult {
     pub snapshot_id: String,
 }
@@ -25,10 +33,11 @@ pub struct PlaylistTracksRef {
 pub struct SimplifiedPlaylist {
     pub collaborative: bool,
     pub external_urls: HashMap<String, String>,
     pub href: String,
     pub id: PlaylistId<'static>,
+    #[serde(deserialize_with = "deserialize_null_default")]
     pub images: Vec<Image>,
     pub name: String,
     pub owner: PublicUser,
     pub public: Option<bool>,
     pub snapshot_id: String,
<!-- gh-comment-id:2025191264 --> @trumank commented on GitHub (Mar 28, 2024): And this patch allows playlists to load for me in `ncspot`: ```patch diff --git a/rspotify-model/src/playlist.rs b/rspotify-model/src/playlist.rs index 07bb7b2..776f1e2 100644 --- a/rspotify-model/src/playlist.rs +++ b/rspotify-model/src/playlist.rs @@ -5,10 +5,18 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use crate::{Followers, Image, Page, PlayableItem, PlaylistId, PublicUser}; +fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error> +where + T: Default + serde::Deserialize<'de>, + D: serde::Deserializer<'de>, +{ + Ok(Option::deserialize(deserializer)?.unwrap_or_default()) +} + /// Playlist result object #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct PlaylistResult { pub snapshot_id: String, } @@ -25,10 +33,11 @@ pub struct PlaylistTracksRef { pub struct SimplifiedPlaylist { pub collaborative: bool, pub external_urls: HashMap<String, String>, pub href: String, pub id: PlaylistId<'static>, + #[serde(deserialize_with = "deserialize_null_default")] pub images: Vec<Image>, pub name: String, pub owner: PublicUser, pub public: Option<bool>, pub snapshot_id: String, ```
Author
Owner

@aome510 commented on GitHub (Mar 28, 2024):

And this patch allows playlists to load for me in ncspot:

diff --git a/rspotify-model/src/playlist.rs b/rspotify-model/src/playlist.rs
index 07bb7b2..776f1e2 100644
--- a/rspotify-model/src/playlist.rs
+++ b/rspotify-model/src/playlist.rs
@@ -5,10 +5,18 @@ use serde::{Deserialize, Serialize};

 use std::collections::HashMap;

 use crate::{Followers, Image, Page, PlayableItem, PlaylistId, PublicUser};

+fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+where
+    T: Default + serde::Deserialize<'de>,
+    D: serde::Deserializer<'de>,
+{
+    Ok(Option::deserialize(deserializer)?.unwrap_or_default())
+}
+
 /// Playlist result object
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
 pub struct PlaylistResult {
     pub snapshot_id: String,
 }
@@ -25,10 +33,11 @@ pub struct PlaylistTracksRef {
 pub struct SimplifiedPlaylist {
     pub collaborative: bool,
     pub external_urls: HashMap<String, String>,
     pub href: String,
     pub id: PlaylistId<'static>,
+    #[serde(deserialize_with = "deserialize_null_default")]
     pub images: Vec<Image>,
     pub name: String,
     pub owner: PublicUser,
     pub public: Option<bool>,
     pub snapshot_id: String,

#[serde(default)] should be enough

<!-- gh-comment-id:2025310972 --> @aome510 commented on GitHub (Mar 28, 2024): > And this patch allows playlists to load for me in `ncspot`: > > ```diff > diff --git a/rspotify-model/src/playlist.rs b/rspotify-model/src/playlist.rs > index 07bb7b2..776f1e2 100644 > --- a/rspotify-model/src/playlist.rs > +++ b/rspotify-model/src/playlist.rs > @@ -5,10 +5,18 @@ use serde::{Deserialize, Serialize}; > > use std::collections::HashMap; > > use crate::{Followers, Image, Page, PlayableItem, PlaylistId, PublicUser}; > > +fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error> > +where > + T: Default + serde::Deserialize<'de>, > + D: serde::Deserializer<'de>, > +{ > + Ok(Option::deserialize(deserializer)?.unwrap_or_default()) > +} > + > /// Playlist result object > #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)] > pub struct PlaylistResult { > pub snapshot_id: String, > } > @@ -25,10 +33,11 @@ pub struct PlaylistTracksRef { > pub struct SimplifiedPlaylist { > pub collaborative: bool, > pub external_urls: HashMap<String, String>, > pub href: String, > pub id: PlaylistId<'static>, > + #[serde(deserialize_with = "deserialize_null_default")] > pub images: Vec<Image>, > pub name: String, > pub owner: PublicUser, > pub public: Option<bool>, > pub snapshot_id: String, > ``` `#[serde(default)]` should be enough
Author
Owner

@trumank commented on GitHub (Mar 28, 2024):

#[serde(default)] will fail if the key is present with a null value:

use serde::Deserialize;

fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
    T: Default + serde::Deserialize<'de>,
    D: serde::Deserializer<'de>,
{
    Ok(Option::deserialize(deserializer)?.unwrap_or_default())
}

#[derive(Debug, Deserialize)]
struct ObjDefault {
    #[serde(default)]
    field: Vec<String>,
}

#[derive(Debug, Deserialize)]
struct ObjCustom {
    #[serde(deserialize_with = "deserialize_null_default")]
    field: Vec<String>,
}

const JSON_NULL: &str = r#"{"field": null}"#;
const JSON_ARRAY: &str = r#"{"field": ["a", "b"]}"#;
const JSON_MISSING: &str = r#"{}"#;

#[test]
fn test_default_null() {
    serde_json::from_str::<ObjDefault>(JSON_NULL).unwrap();
}
#[test]
fn test_default_array() {
    serde_json::from_str::<ObjDefault>(JSON_ARRAY).unwrap();
}
#[test]
fn test_default_missing() {
    serde_json::from_str::<ObjDefault>(JSON_MISSING).unwrap();
}
#[test]
fn test_custom_null() {
    serde_json::from_str::<ObjCustom>(JSON_NULL).unwrap();
}
#[test]
fn test_custom_array() {
    serde_json::from_str::<ObjCustom>(JSON_ARRAY).unwrap();
}
#[test]
fn test_custom_missing() {
    serde_json::from_str::<ObjCustom>(JSON_MISSING).unwrap();
}
$ cargo test
running 6 tests
test test_custom_array ... ok
test test_custom_missing ... FAILED
test test_default_missing ... ok
test test_custom_null ... ok
test test_default_array ... ok
test test_default_null ... FAILED

failures:

---- test_custom_missing stdout ----
thread 'test_custom_missing' panicked at serde-test/src/main.rs:51:53:
called `Result::unwrap()` on an `Err` value: Error("missing field `field`", line: 1, column: 2)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- test_default_null stdout ----
thread 'test_default_null' panicked at serde-test/src/main.rs:31:51:
called `Result::unwrap()` on an `Err` value: Error("invalid type: null, expected a sequence", line: 1, column: 14)


failures:
    test_custom_missing
    test_default_null

test result: FAILED. 4 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
<!-- gh-comment-id:2025391563 --> @trumank commented on GitHub (Mar 28, 2024): `#[serde(default)]` will fail if the key is present with a null value: ```rust use serde::Deserialize; fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error> where T: Default + serde::Deserialize<'de>, D: serde::Deserializer<'de>, { Ok(Option::deserialize(deserializer)?.unwrap_or_default()) } #[derive(Debug, Deserialize)] struct ObjDefault { #[serde(default)] field: Vec<String>, } #[derive(Debug, Deserialize)] struct ObjCustom { #[serde(deserialize_with = "deserialize_null_default")] field: Vec<String>, } const JSON_NULL: &str = r#"{"field": null}"#; const JSON_ARRAY: &str = r#"{"field": ["a", "b"]}"#; const JSON_MISSING: &str = r#"{}"#; #[test] fn test_default_null() { serde_json::from_str::<ObjDefault>(JSON_NULL).unwrap(); } #[test] fn test_default_array() { serde_json::from_str::<ObjDefault>(JSON_ARRAY).unwrap(); } #[test] fn test_default_missing() { serde_json::from_str::<ObjDefault>(JSON_MISSING).unwrap(); } #[test] fn test_custom_null() { serde_json::from_str::<ObjCustom>(JSON_NULL).unwrap(); } #[test] fn test_custom_array() { serde_json::from_str::<ObjCustom>(JSON_ARRAY).unwrap(); } #[test] fn test_custom_missing() { serde_json::from_str::<ObjCustom>(JSON_MISSING).unwrap(); } ``` ```console $ cargo test running 6 tests test test_custom_array ... ok test test_custom_missing ... FAILED test test_default_missing ... ok test test_custom_null ... ok test test_default_array ... ok test test_default_null ... FAILED failures: ---- test_custom_missing stdout ---- thread 'test_custom_missing' panicked at serde-test/src/main.rs:51:53: called `Result::unwrap()` on an `Err` value: Error("missing field `field`", line: 1, column: 2) note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ---- test_default_null stdout ---- thread 'test_default_null' panicked at serde-test/src/main.rs:31:51: called `Result::unwrap()` on an `Err` value: Error("invalid type: null, expected a sequence", line: 1, column: 14) failures: test_custom_missing test_default_null test result: FAILED. 4 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ```
Author
Owner

@aome510 commented on GitHub (Mar 28, 2024):

I see, thanks for testing it.

<!-- gh-comment-id:2025424548 --> @aome510 commented on GitHub (Mar 28, 2024): I see, thanks for testing it.
Author
Owner

@Icelk commented on GitHub (Apr 1, 2024):

In the meantime, one may use the API to check which playlist is the culprit. Go the the spotify API documentation link below and test the query with limit = 50 offset = 0 on your own account (you need to be logged in):
https://developer.spotify.com/documentation/web-api/reference/get-a-list-of-current-users-playlists
Then Ctrl+F for "images": null

<!-- gh-comment-id:2029552511 --> @Icelk commented on GitHub (Apr 1, 2024): In the meantime, one may use the API to check which playlist is the culprit. Go the the spotify API documentation link below and test the query with limit = 50 offset = 0 on your own account (you need to be logged in): <https://developer.spotify.com/documentation/web-api/reference/get-a-list-of-current-users-playlists> Then Ctrl+F for `"images": null`
Author
Owner

@00alia00 commented on GitHub (Apr 8, 2024):

@Icelk Thanks, that was a life saver! An empty playlist (and therefore no image) was killing it for me! Adding an image to the playlist fixed it.

<!-- gh-comment-id:2041748030 --> @00alia00 commented on GitHub (Apr 8, 2024): @Icelk Thanks, that was a life saver! An empty playlist (and therefore no image) was killing it for me! Adding an image to the playlist fixed it.
Author
Owner

@trumank commented on GitHub (Jun 3, 2024):

I believe this should be closed now that #480 is merged?

<!-- gh-comment-id:2145561200 --> @trumank commented on GitHub (Jun 3, 2024): I believe this should be closed now that #480 is merged?
Author
Owner

@ramsayleung commented on GitHub (Jun 3, 2024):

Closing this issue as the problem has been resolved in #480 .

<!-- gh-comment-id:2145737499 --> @ramsayleung commented on GitHub (Jun 3, 2024): Closing this issue as the problem has been resolved in #480 .
Author
Owner

@flrgh commented on GitHub (Jun 3, 2024):

Thanks @ramsayleung! Would you be able to cut a patch release for this fix? I have been sourcing this dep from master, but it would be nice to switch back to a release.

<!-- gh-comment-id:2145757423 --> @flrgh commented on GitHub (Jun 3, 2024): Thanks @ramsayleung! Would you be able to cut a patch release for this fix? I have been sourcing this dep from master, but it would be nice to switch back to a release.
Author
Owner

@ramsayleung commented on GitHub (Jun 4, 2024):

The patch release v.0.13.2 has been release #485 :-)

<!-- gh-comment-id:2146633619 --> @ramsayleung commented on GitHub (Jun 4, 2024): The patch release `v.0.13.2` has been release #485 :-)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/rspotify#153
No description provided.