rspotify: json parse error when getting playlist with no image

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

About this issue

  • Original URL
  • State: open
  • Created 4 months ago
  • Comments: 16 (10 by maintainers)

Commits related to this issue

Most upvoted comments

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

#[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