{"record":{"id":"87e59f337002cf7f","repo":"remotion-dev/remotion","slug":"expected-an-array-of-associated-playlists","errorCode":null,"errorMessage":"Expected an array of associated playlists","messagePattern":"Expected an array of associated playlists","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/m3u/select-stream.ts","lineNumber":34,"sourceCode":"\toptions: SelectM3uAssociatedPlaylistsFnOptions,\n) => M3uAssociatedPlaylist[] | Promise<M3uAssociatedPlaylist[]>;\n\nexport const selectAssociatedPlaylists = async ({\n\tplaylists,\n\tfn,\n\tskipAudioTracks,\n}: {\n\tplaylists: M3uAssociatedPlaylist[];\n\tfn: SelectM3uAssociatedPlaylistsFn;\n\tskipAudioTracks: boolean;\n}): Promise<M3uAssociatedPlaylist[]> => {\n\tif (playlists.length < 1) {\n\t\treturn Promise.resolve([]);\n\t}\n\n\tconst streams = await fn({associatedPlaylists: playlists});\n\tif (!Array.isArray(streams)) {\n\t\tthrow new Error('Expected an array of associated playlists');\n\t}\n\n\tconst selectedStreams: M3uAssociatedPlaylist[] = [];\n\tfor (const stream of streams) {\n\t\tif (stream.isAudio && skipAudioTracks) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!playlists.find((playlist) => playlist.src === stream.src)) {\n\t\t\tthrow new Error(\n\t\t\t\t`The associated playlist ${JSON.stringify(streams)} cannot be selected because it was not in the list of selectable playlists`,\n\t\t\t);\n\t\t}\n\n\t\tselectedStreams.push(stream);\n\t}\n\n\treturn selectedStreams;","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/m3u/select-stream.ts#L16-L52","documentation":"Thrown by `selectAssociatedPlaylists` when the user-supplied `selectM3uAssociatedPlaylists` callback returns a value that is not an array. The callback contract (`SelectM3uAssociatedPlaylistsFn`) requires returning `M3uAssociatedPlaylist[]`; returning `undefined`, `null`, an object, or a single non-array value triggers this guard.","triggerScenarios":"Providing a custom `selectM3uAssociatedPlaylists` option to `parseMedia()` that returns `null`, `undefined`, a single playlist object, or any non-array value from the callback function.","commonSituations":"A custom callback that forgets to wrap a single selection in an array. A callback that returns the result of `.find()` (single element) instead of `.filter()` (array). A callback that conditionally returns `undefined` on some branch.","solutions":["Ensure your `selectM3uAssociatedPlaylists` callback always returns an array, even for a single selection.","Use `Array.isArray()` on the return value before returning it, or spread a single result: `return [playlist]`.","Use the default `defaultSelectM3uAssociatedPlaylists` if you don't need custom logic.","Type-check the callback against `SelectM3uAssociatedPlaylistsFn` to let TypeScript catch this at compile time."],"exampleFix":"// before\nselectM3uAssociatedPlaylists: ({associatedPlaylists}) => {\n  return associatedPlaylists.find(p => p.default); // returns object, not array\n}\n\n// after\nselectM3uAssociatedPlaylists: ({associatedPlaylists}) => {\n  return associatedPlaylists.filter(p => p.default); // returns array\n}","handlingStrategy":"type-guard","validationCode":"// Wrap your callback to guarantee array return\nimport {\n  defaultSelectM3uAssociatedPlaylists,\n  type SelectM3uAssociatedPlaylistsFn,\n} from '@remotion/media-parser';\n\nconst safeSelect: SelectM3uAssociatedPlaylistsFn = async (opts) => {\n  const result = await myCustomSelect(opts);\n  if (!Array.isArray(result)) {\n    throw new TypeError('selectM3uAssociatedPlaylists must return an array');\n  }\n  return result;\n};","typeGuard":"import type {M3uAssociatedPlaylist} from '@remotion/media-parser';\n\nfunction isPlaylistArray(value: unknown): value is M3uAssociatedPlaylist[] {\n  return Array.isArray(value) && value.every(\n    (v) => v !== null && typeof v === 'object' && 'src' in v\n  );\n}","tryCatchPattern":"try {\n  await parseMedia({src, selectM3uAssociatedPlaylists: myFn});\n} catch (e) {\n  if (e instanceof Error && e.message === 'Expected an array of associated playlists') {\n    console.error('Your selectM3uAssociatedPlaylists callback must return an array.');\n  }\n  throw e;\n}","preventionTips":["Always return an array from selectM3uAssociatedPlaylists, even for a single selection.","Use TypeScript types (SelectM3uAssociatedPlaylistsFn) to catch this at compile time.","Prefer .filter() over .find() in playlist selection callbacks.","Use the default callback if you don't need custom selection logic."],"tags":["hls","m3u8","callback-contract","select-playlist","type-error"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}