Skip to content

Fix: Search crashes due to recent Spotify API changes (null items, missing tracks/publisher) #721

@juanmalopman

Description

@juanmalopman

(Note: I am running this on top of PR #720 (#720) since the master branch currently cannot get past the login screen. Once logged in via that PR's WebAPI fix, I ran into these search crashes.)

Describe the bug
When searching any song/artist/album:
Error: json: invalid type: null, expected struct Playlist at line 1 column 16998
...and after fixing it:
Error: json: missing field 'tracks' at line 1 column 18887

To Reproduce
Search for any song.

Expected behavior
Return a list of results.

Environment

  • OS: Win 11

Additional context

I guess Spotify changed their API payloads, causing psst to crash immediately when using the Search function.

I traced the panics to three specific API payload changes and successfully fixed them locally:

1. Search arrays occasionally return null items
The items array sometimes contains null instead of a valid struct (e.g., if a track is region-blocked).
Fix: In psst-gui/src/data/utils.rs, I updated the Page<T> struct to safely drop nulls using a custom deserializer:

#[derive(Deserialize, Default)]
pub struct Page<T: Clone> {
    #[serde(
        deserialize_with = "deserialize_ignore_nulls",
        bound = "T: serde::Deserialize<'de>"
    )]
    pub items: Vector<T>,
    
    pub limit: usize,
    pub offset: usize,
    pub total: usize,
}

And added this helper:

pub fn deserialize_ignore_nulls<'de, D, T>(deserializer: D) -> Result<Vector<T>, D::Error>
where
    D: serde::Deserializer<'de>,
    T: serde::Deserialize<'de> + Clone,
{
    let opt_vec: Option<Vec<Option<T>>> = Option::deserialize(deserializer)?;
    Ok(opt_vec.unwrap_or_default().into_iter().flatten().collect())
}
  1. Playlists occasionally omit the tracks field entirely
    Fix: In psst-gui/src/data/playlist.rs, added #[serde(default)] to pub track_count: Option and made the deserialize_track_count helper gracefully handle nulls via Option::deserialize.
#[derive(Clone, Debug, Data, Lens, Deserialize)]
pub struct Playlist {
    pub id: Arc<str>,
    pub name: Arc<str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub images: Option<Vector<Image>>,
    #[serde(deserialize_with = "deserialize_description")]
    pub description: Arc<str>,
    #[serde(default)]
    #[serde(rename = "tracks")]
    #[serde(deserialize_with = "deserialize_track_count")]
    pub track_count: Option<usize>,
    pub owner: PublicUser,
    pub collaborative: bool,
    #[serde(rename = "public")]
    pub public: Option<bool>,
}
  1. Shows/Podcasts occasionally omit the publisher field
    Fix: In psst-gui/src/data/show.rs, added #[serde(default)] above pub publisher: Arc.
#[derive(Clone, Data, Lens, Deserialize)]
pub struct Show {
    pub id: Arc<str>,
    pub name: Arc<str>,
    pub images: Vector<Image>,
    #[serde(default)]
    pub publisher: Arc<str>,
    pub description: Arc<str>,
    pub total_episodes: Option<usize>,
}

These three simple serde additions completely restored Search functionality for me! Can't load an Artist page but can use the app for the most part.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions