{"record":{"id":"f0788a76f32935af","repo":"RocketChat/Rocket.Chat","slug":"failed-to-resume-audio-playback","errorCode":null,"errorMessage":"Failed to resume audio playback:","messagePattern":"Failed to resume audio playback:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"apps/meteor/client/providers/MediaPlayerProvider/MediaPlayerProvider.tsx","lineNumber":65,"sourceCode":"\t\tif (trackRef.current?.id !== next.id) {\n\t\t\tsetTrack(next);\n\t\t\tsetCurrentTime(0);\n\t\t\tsetDuration(0);\n\t\t\taudio.src = next.url;\n\t\t\taudio.load();\n\t\t}\n\n\t\taudio.playbackRate = playbackRate;\n\t\taudio.play().catch((err) => console.warn('Failed to start audio playback:', err));\n\t});\n\n\tconst toggle = useStableCallback(() => {\n\t\tconst audio = audioRef.current;\n\t\tif (!audio || !trackRef.current) {\n\t\t\treturn;\n\t\t}\n\t\tif (audio.paused) {\n\t\t\taudio.play().catch((err) => console.warn('Failed to resume audio playback:', err));\n\t\t} else {\n\t\t\taudio.pause();\n\t\t}\n\t});\n\n\tconst seek = useStableCallback((time: number) => {\n\t\tconst audio = audioRef.current;\n\t\tif (!audio) {\n\t\t\treturn;\n\t\t}\n\t\taudio.currentTime = Math.max(0, Math.min(time, audio.duration || time));\n\t});\n\n\tconst cyclePlaybackRate = useStableCallback(() => {\n\t\tsetPlaybackRate((rate) => {\n\t\t\tconst idx = PLAYBACK_RATES.indexOf(rate as (typeof PLAYBACK_RATES)[number]);\n\t\t\tconst nextRate = PLAYBACK_RATES[(idx + 1) % PLAYBACK_RATES.length];\n\t\t\tif (audioRef.current) {","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/client/providers/MediaPlayerProvider/MediaPlayerProvider.tsx#L47-L83","documentation":"Client-side: the player's toggle handler called audio.play() to resume a paused track and the promise rejected. Unlike programmatic starts, this runs inside a user gesture, so the usual causes are media-level failures: source unloaded or expired (src removed, link expired), the fetch of media data aborted by a new load request, or the element left in a state where play() cannot start.","triggerScenarios":"Resuming after the underlying file URL expired; pressing play while a track switch is mid-load (AbortError: play() interrupted by a new load request); playbackRate or currentTime set to an unsupported value before resume; source removed from the element while paused.","commonSituations":"Audio attachments whose authenticated URLs expire during a long pause; quick toggle/track-change races; mobile browsers unloading media to save memory.","solutions":["Check the err.name in console: AbortError is a benign race — retry play(); NotSupportedError means the source is bad","Re-set audio.src with a fresh URL before resuming if links can expire","Avoid starting a new load while a play() promise is pending; chain the operations instead","For unrecoverable sources, surface an error state in the UI instead of retrying"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isAbortError(err: unknown): err is DOMException {\n\treturn err instanceof DOMException && err.name === 'AbortError';\n}","tryCatchPattern":"audio.play().catch((err: unknown) => {\n\tif (isAbortError(err)) return; // benign: superseded by a new load request\n\tif (err instanceof DOMException && err.name === 'NotSupportedError') {\n\t\tshowSourceErrorUI();\n\t\treturn;\n\t}\n\tconsole.warn('Failed to resume audio playback:', err);\n});","preventionTips":["Do not start a new load() while a play() promise is pending on the same element","Re-acquire fresh signed URLs for long-paused audio before resume","Classify DOMException names (AbortError/NotAllowedError/NotSupportedError) rather than treating all rejections alike"],"tags":["audio","browser","client","media","html5-audio","autoplay"],"backgroundTag":"play-promise-rejected","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}