Skip to content

Fatal exception in SPTAppRemoteUserCapabilities when can_play_on_demand is null #467

Description

@edwinveger

Summary

The SDK crashes for roughly 0.5% of our users with the following fatal exception:

Fatal Exception: Malformed payload
Expected non-optional parameter can_play_on_demand to be of type NSNumber, but found (null)

We are using the SDK in the intended way: users authorize our app to play music on their behalf. Despite this, the SDK appears to receive a payload from Spotify where can_play_on_demand is null, and it crashes rather than falling back to a sensible default (e.g. false).

Expected behavior

When the backend returns a null value for can_play_on_demand, the SDK should default to false (or otherwise surface the missing capability gracefully) instead of throwing a fatal exception that takes down the host application.

Actual behavior

The SDK throws a fatal exception the moment capabilities.canPlayOnDemand is accessed, crashing our app.

Reproduction

The crash occurs in our SPTAppRemoteUserAPIDelegate implementation when reading canPlayOnDemand from the capabilities passed into the delegate callback:

extension SpotifyClient: SPTAppRemoteUserAPIDelegate {
    nonisolated func userAPI(
        _ userAPI: any SPTAppRemoteUserAPI,
        didReceive capabilities: any SPTAppRemoteUserCapabilities
    ) {
        Task { @MainActor in
            self.hasOnDemandCapability = capabilities.canPlayOnDemand // <-- fatal exception
            // …
        }
    }
}

We need canPlayOnDemand to tailor the user experience, so there is no workaround on our side — the property cannot be safely read at all for this subset of users.

We don't have information about which specific API call triggers the malformed payload; the crash surfaces only through the delegate callback.

Environment

  • Spotify iOS SDK: 5.0.1
  • iOS versions seen in the wild: 18.6, 18.7, 26.1, 26.2, 26.3, and others
  • Affected users: ~0.5% of sessions

Suggested fix

Treat a null can_play_on_demand in the incoming payload as false (or expose it as an optional) rather than crashing. This seems like a straightforward defensive fix on the SDK side.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions