{"record":{"id":"e222fbd9e2481b3f","repo":"jitsi/jitsi-meet","slug":"noaudiotrackfound","errorCode":null,"errorMessage":"NoAudioTrackFound","messagePattern":"NoAudioTrackFound","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"react/features/recording/components/Recording/LocalRecordingManager.web.ts","lineNumber":233,"sourceCode":"            const gdmVideoTrack = gdmStream.getVideoTracks()[0];\n\n            if (supportsCaptureHandle) {\n                const isBrowser = gdmVideoTrack.getSettings().displaySurface === 'browser';\n                const matchesHandle = (supportsCaptureHandle // @ts-ignore\n                    && gdmVideoTrack.getCaptureHandle()?.handle === `JitsiMeet-${tabId}`);\n\n                if (!isBrowser || !matchesHandle) {\n                    gdmStream.getTracks().forEach((track: MediaStreamTrack) => track.stop());\n                    throw new Error('WrongSurfaceSelected');\n                }\n            }\n\n            this.initializeAudioMixer();\n\n            const gdmAudioTrack = gdmStream.getAudioTracks()[0];\n\n            if (!gdmAudioTrack) {\n                throw new Error('NoAudioTrackFound');\n            }\n\n            this.addAudioTrackToLocalRecording(gdmAudioTrack);\n\n            const localAudioTrack = getLocalTrack(tracks, MEDIA_TYPE.AUDIO)?.jitsiTrack?.track;\n\n            if (localAudioTrack) {\n                this.addAudioTrackToLocalRecording(localAudioTrack);\n            }\n\n            this.stream = new MediaStream([\n                ...this.audioDestination?.stream.getAudioTracks() || [],\n                gdmVideoTrack\n            ]);\n        }\n\n        this.recorder = new MediaRecorder(this.stream, {\n            // @ts-ignore","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/jitsi/jitsi-meet/blob/98de6219cc7ddbe07ace9fde045aff90a242ba01/react/features/recording/components/Recording/LocalRecordingManager.web.ts#L215-L251","documentation":"After a display-media stream is obtained for local recording, the code expects at least one audio track in the gdmStream (the tab audio shared via getDisplayMedia). If the user shared the tab without audio (didn't tick 'Share tab audio' / 'Share system audio'), getAudioTracks() is empty and 'NoAudioTrackFound' is thrown before the audio mixer is fed.","triggerScenarios":"Calling startLocalRecording after getDisplayMedia succeeded but the user did not enable audio sharing in the picker, or the browser/policy stripped the audio track (e.g. some Linux setups, or displaySurface configurations that don't offer tab audio).","commonSituations":"User forgets to check 'Share tab audio' in Chrome's dialog; browser variant that doesn't expose tab audio; enterprise policy disabling display audio capture; expecting mic audio to substitute for gdm audio.","solutions":["Prompt the user to enable 'Share audio' / 'Share tab audio' when the picker opens, and catch this error to show that instruction and retry","Request audio explicitly in getDisplayMedia constraints (audio: true with preferCurrentTab) so the picker defaults audio on","Validate gdmStream.getAudioTracks().length before proceeding and fall back to mic-only recording if acceptable","On unsupported configurations, surface a clear notification that tab audio sharing is required for local recording"],"exampleFix":"// before\nconst gdmAudioTrack = gdmStream.getAudioTracks()[0];\nif (!gdmAudioTrack) {\n    throw new Error('NoAudioTrackFound');\n}\n\n// after\nconst gdmAudioTrack = gdmStream.getAudioTracks()[0];\nif (!gdmAudioTrack) {\n    dispatch(showErrorNotification({\n        titleKey: 'localRecording.noAudio',\n        descriptionKey: 'localRecording.shareTabAudio'\n    }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));\n    gdmStream.getTracks().forEach(t => t.stop());\n    return;\n}","handlingStrategy":"validation","validationCode":"const gdmStream = await navigator.mediaDevices.getDisplayMedia({\n    video: true,\n    audio: true, // ask for tab audio up front\n    preferCurrentTab: true\n});\nif (gdmStream.getAudioTracks().length === 0) {\n    // tell user to tick 'Share tab audio' and retry instead of proceeding\n}","typeGuard":"const hasSharedAudio = (s: MediaStream): boolean => s.getAudioTracks().length > 0;","tryCatchPattern":"try {\n    await manager.startLocalRecording();\n} catch (e: unknown) {\n    if (e instanceof Error && e.message === 'NoAudioTrackFound') {\n        showError('Enable \\'Share tab audio\\' in the sharing dialog and try again.');\n    } else {\n        throw e;\n    }\n}","preventionTips":["Always request audio: true in getDisplayMedia constraints","Instruct users to check the 'share audio' checkbox before confirming","Validate getAudioTracks().length immediately after the picker resolves"],"tags":["getdisplaymedia","tab-audio","audio-mixer","local-recording","screen-capture"],"backgroundTag":"missing-shared-tab-audio","analyzedSha":"98de6219cc7ddbe07ace9fde045aff90a242ba01","analyzedAt":"2026-08-28T15:15:59.482Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}