jitsi/jitsi-meet · error · Error
NoLocalStreams
Error message
NoLocalStreams
What it means
Thrown by startLocalRecording on web when the user has no live local audio or video track to record. Before starting a local recording, the manager checks the local tracks from redux; video tracks that are not in readyState 'live' are discarded. If both audio and video are absent (or ended), recording cannot proceed and 'NoLocalStreams' is raised.
Source
Thrown at react/features/recording/components/Recording/LocalRecordingManager.web.ts:177
this.writableStream = await this.fileHandle?.createWritable();
const supportsCaptureHandle = !isEmbedded();
const tabId = uuidV4();
this.selfRecording.on = onlySelf;
let gdmStream: MediaStream = new MediaStream();
const tracks = getTrackState(getState());
if (onlySelf) {
const audioTrack: MediaStreamTrack | undefined = getLocalTrack(tracks, MEDIA_TYPE.AUDIO)?.jitsiTrack?.track;
let videoTrack: MediaStreamTrack | undefined = getLocalTrack(tracks, MEDIA_TYPE.VIDEO)?.jitsiTrack?.track;
if (videoTrack && videoTrack.readyState !== 'live') {
videoTrack = undefined;
}
if (!audioTrack && !videoTrack) {
throw new Error('NoLocalStreams');
}
this.selfRecording.withVideo = Boolean(videoTrack);
const localTracks: MediaStreamTrack[] = [];
audioTrack && localTracks.push(audioTrack.clone());
videoTrack && localTracks.push(videoTrack.clone());
this.stream = new MediaStream(localTracks);
} else {
if (supportsCaptureHandle) {
// @ts-ignore
navigator.mediaDevices.setCaptureHandleConfig({
handle: `JitsiMeet-${tabId}`,
permittedOrigins: [ '*' ]
});
}
gdmStream = await navigator.mediaDevices.getDisplayMedia({View on GitHub (pinned to 98de6219cc)
Solutions
- Verify the participant has at least one live local track (unmuted audio or active video) before showing/enabling the local recording button
- Check track.readyState === 'live' on the raw jitsiTrack.track before calling startLocalRecording
- If permissions were denied, re-request mic/camera access and retry once tracks exist
- Handle the thrown error in the caller to show a 'you need at least one active mic or camera' notification instead of crashing
Example fix
// before
await localRecordingManager.startLocalRecording();
// after
const tracks = getState()['features/base/tracks'];
const audio = getLocalTrack(tracks, MEDIA_TYPE.AUDIO)?.jitsiTrack?.track;
const video = getLocalTrack(tracks, MEDIA_TYPE.VIDEO)?.jitsiTrack?.track;
const hasLive = t => t && t.readyState === 'live';
if (!hasLive(audio) && !hasLive(video)) {
dispatch(showErrorNotification({ titleKey: 'localRecording.noStreams' }));
} else {
await localRecordingManager.startLocalRecording();
} Defensive patterns
Strategy: validation
Validate before calling
const tracks = getState()['features/base/tracks'];
const audio = getLocalTrack(tracks, MEDIA_TYPE.AUDIO)?.jitsiTrack?.track;
const video = getLocalTrack(tracks, MEDIA_TYPE.VIDEO)?.jitsiTrack?.track;
const hasLiveTrack = (audio && audio.readyState === 'live')
|| (video && video.readyState === 'live');
if (!hasLiveTrack) {
// show 'enable mic or camera first' notification instead of calling
} Type guard
const isLiveTrack = (t?: MediaStreamTrack | null): t is MediaStreamTrack =>
Boolean(t) && t!.readyState === 'live'; Try / catch
try {
await manager.startLocalRecording();
} catch (e: unknown) {
if (e instanceof Error && e.message === 'NoLocalStreams') {
showError('Enable your microphone or camera before recording.');
} else {
throw e;
}
} Prevention
- Disable/gate the local-record button until a live local track exists in redux
- Subscribe to track ended/muted events to update button state
- Re-request media permissions before starting the recording flow
When it happens
Trigger: Calling startLocalRecording() when the local participant's audio is muted-without-track (or track ended) and video is disabled or its MediaStreamTrack.readyState !== 'live'. This includes calling before media permission was granted, after stopping all tracks, or when the user joined in audio-only/muted mode with no gdm audio source.
Common situations: User joins with mic/camera permissions denied or revoked mid-call; track was stopped and disposed; startLocalRecording invoked from UI before waitForInitialization/local tracks are ready; browser blocked getUserMedia.
Related errors
AI-assisted analysis of jitsi/jitsi-meet@98de6219cc (2026-08-28).
Data as JSON: /api/errors/781344ed67d6a172.
Report an issue: GitHub.