Fix: Search crashes due to recent Spotify API changes (null items, missing tracks/publisher)
(Note: I am running this on top of PR #720 (https://github.com/jpochyla/psst/pull/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())
}- 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>,
}- 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.
Source: jpochyla/psst