Skip to main content
Version: v2.10.3

Migrating to 2.10.3

This guide covers the stable 2.10.2 to 2.10.3 upgrade. Existing Lavalink v4 applications do not need a second Node class or a new storage configuration. They do need to account for the corrected public types and playlist shape.

Install and Retain a Rollback​

npm install [email protected]

Review and retain your dependency lockfile. Reverting to [email protected] also requires reverting code that uses native NodeLink methods or corrected 2.10.3-specific shapes. Do not publish or upgrade a production bot solely because the package builds.

Playlist Metadata​

Previously, playlistInfo was typed/filled as plugin metadata. It now contains the actual Lavalink playlist information. Move plugin-field reads to pluginInfo.

if ("playlist" in result) {
const { playlist } = result;

// Core protocol information:
console.log(playlist.playlistInfo.name);
console.log(playlist.playlistInfo.selectedTrack);

// Extensible plugin metadata, validated before use:
const url = playlist.pluginInfo.url;
if (typeof url === "string") {
console.log(url);
}
}

PlaylistInfoData is a single { name, selectedTrack } object, not an array. A selected index of -1 means no selected track.

Nullable Track Fields​

Track URI, artwork URL, and ISRC can be null, even though modern providers usually set a URI. Keep that protocol contract in application code.

if (track.uri) {
embed.setURL(track.uri);
}
if (track.artworkUrl) {
embed.setThumbnail(track.artworkUrl);
}
const isYouTube = track.uri?.includes("youtube.com") ?? false;

Do not cast away nullability or substitute undefined in the library's protocol types. Choose application-specific fallbacks when rendering a missing URL. Raw TrackData.userData is exposed on built tracks as Track.customData.

Search Results and Gateway Messages​

Narrow SearchResult by loadType or property checks. Empty/backend-error load results contain tracks: []; transport failures still reject.

if (result.loadType === "empty" || result.loadType === "error") {
return;
}
await player.queue.add(result.tracks);

Gateway data is now a discriminated union rather than a stats-shaped message. Read stats only on op: "stats", player state only on op: "playerUpdate", and event-specific properties only after narrowing the event.

Remote LavaPlayer.track and NodeStats.frameStats may be null. Lyrics, chapter, and SponsorBlock callback tracks may also be null.

Separate Native Search APIs​

Continue using SearchPlatform for shared searches. Use NodeLinkSearchPlatform, NodeLinkRecommendationPlatform, and NodeLinkSearchType for native capabilities. Shared string values still permit either backend; native prefixes/modifiers require a connected eligible NodeLink.

NodeLink Spotify recommendations use sprec:seed_tracks=.... Lavalink's raw sprec:mix:track:... workaround stays on Lavalink. See search examples.

Guard Native Actions in Mixed Pools​

if (player.node.isNodeLink) {
await player.setNodeLinkLoudnessNormalizer(true);
const chapters = await player.getNodeLinkChapters();
}

Pin native-feature players with nodeIdentifier when creating them. Recheck after node moves. Do not assume a native search also pins playback.

Mixer layers use 0-1 volume, not the main player's 0-1000 scale. preloadNextTrack() does not enqueue a track; keep the local next track aligned. Use explicit NodeLink aliases to make native-only code apparent.

Plugin Filters and Lyrics​

Nonempty setPluginFilters() now checks for a matching advertised plugin. By default it expects LavaDSPX-Plugin aliases; provide the advertised plugin name for another plugin. Empty calls clear without that requirement.

On NodeLink, use node.getLyrics(track, false, language) and narrow NodeLinkGetLyrics. The current player.getCurrentLyrics() return type does not reflect its unnormalized native runtime result. See lyrics handling.

Sessions and Restores​

Wait for node readiness before calling session-scoped REST helpers. getPlayers() returns an empty array without a session; some other helpers currently return null at runtime despite their declared signatures.

Autoplay settings and requester data are now preserved through state restoration. Check the first restored autoplay request and wrapper-specific user resolution when testing JSON or Redis state. No new storage setup is required.

Validate the Upgrade​

Run your bot's typecheck/tests and the release validation checklist on Lavalink, NodeLink, and a mixed pool before promotion.


Older Migration Guide

🔥 Upgrading to MagmaStream v2.10.0 — Migration Guide​

warning

This release contains breaking changes. Review everything below before upgrading.
Lables:
🔴 - Breaking
🟡 - Changes
🟢 - New


🔴 Renamed Options​

PlayerOptions:

  • guild → guildId
  • voiceChannel → voiceChannelId
  • textChannel → textChannelId
  • node → nodeIdentifier

NodeOptions:

  • secure → useSSL
  • resumeStatus → enableSessionResumeOption
  • resumeTimeout → sessionTimeoutSeconds
  • retryAmount → maxRetryAttempts
  • retryDelay → retryDelayMs
  • priority → nodePriority

ManagerOptions:

  • autoPlay → playNextOnEnd
  • usePriority → enablePriorityMode
  • replaceYouTubeCredentials → normalizeYouTubeTitles
  • plugins → enabledPlugins

🔴 Queue Overhaul​

The old Queue class has been removed. You must now pick a storage backend explicitly:

  • MemoryQueue — in-memory, synchronous methods (closest to old behaviour)
  • JsonQueue — persists to disk, async methods
  • RedisQueue — persists to Redis, async methods
warning

If you use JsonQueue or RedisQueue, all queue calls need await.


🔴 Filter API​

Filters now take an explicit boolean instead of being toggle calls:

Before

player.filters.nightcore()

After

player.filters.nightcore(true)
player.filters.nightcore(false)

bassBoost now takes a stage from -3 to 3 instead of being a toggle: player.filters.bassBoost(3) = max boost, player.filters.bassBoost(0) = disabled


🟡 Error Handling​

All errors are now MagmaStreamError instances with structured codes and context. Replace any TypeError / RangeError catches with MagmaStreamError.


🟢 What's been added​

  • Library wrappers: DiscordJSManager, DiscordenoManager, ErisManager, OceanicManager, SeyfertManager
  • Abstract Plugin base class with load() / unload() methods
  • Redis-backed session and queue storage
  • New filters: demon, earrape, doubletime, chipmunk, daycore, darthvader, electronic, radio, tremolo, pop, party

Questions?​

  • 📄 Full docs here
  • ❔ Join our Discord — we're happy to help.