Description
After starting share screen then exiting it, then restarting it a few times, suddenly it stops working it doesn’t reach the finally of the promise and there is no error message as well
Browser Console Error
No error message
Which Web Video SDK version?
“@zoom /videosdk”: “^2.2.12”
Video SDK Code Snippets
zoomSession
.startShareScreen(element, options)
.catch((error) => {
console.log(error)
})
.finally(() => {
isLoading = false
})
To Reproduce(If applicable)
Steps to reproduce the behavior:
Start share screen
Exit via browser bar
Do this a couple of times then you will be unable to share your screen
No error message
Device (please complete the following information):
Macbook Air M1
OS: macOS 26.2
Browser: Chrome and Firefox
Browser Version
Chrome Version 144.0.7559.133 (Official Build) (arm64)
Firefox Version147.0.3 Build ID 20260203002554
Additional context
Session ID: nrgPAhU2S/asNDG6SRENrA==
vic.yang
(Vic)
February 13, 2026, 11:06am
2
Hi @matthew.offshorly
Thanks for your feedback.
nrgPAhU2S/asNDG6SRENrA==
We are analyzing the logs and investigating the root cause. We will keep you updated.
Thanks
Vic
Hi @vic.yang can you also check this Session ID? 9UY6cvowTxWQOwo89GZhlw==
We are encountering an empty share screen for the sharer
Steps to replicate:
User #1 starts share screen then stop share screen using browser control
User #2 repeats step 1
User #1 repeats step 1, 4x times
Then User #1 will have an empty share screen
Screenshot of screen share not rendering after 4th share screen
Code Snippet on share screen implementation
// Screen Sharing Implementation for Zoom Video SDK
// ============================================
// 1. Screen Element References & State
// ============================================
const screenVideoElement = useTemplateRef<HTMLVideoElement>('screenVideoElement')
const screenCanvasElement = useTemplateRef<HTMLCanvasElement>('screenCanvasElement')
const isShareScreenWithVideoElement = ref(false)
const isShareScreenLoading = ref(false)
// ============================================
// 2. Screen Element Management
// ============================================
const setScreenElements = (
newScreenVideoElement: HTMLVideoElement,
newScreenCanvasElement: HTMLCanvasElement
) => {
screenVideoElement.value = newScreenVideoElement
screenCanvasElement.value = newScreenCanvasElement
}
const clearScreenElements = () => {
screenVideoElement.value = null
screenCanvasElement.value = null
}
const getScreenVideoElement = () => screenVideoElement.value
const getScreenCanvasElement = () => screenCanvasElement.value
// ============================================
// 3. Reset Screen Elements (workaround)
// ============================================
const resetScreenElements = async () => {
await delay(200)
isScreenReset.value = true
await nextTick()
await delay(200)
clearScreenElements()
isScreenReset.value = false
await nextTick()
await delay(200)
initScreenElements()
}
const initScreenElements = () => {
if (screenVideoElement.value && screenCanvasElement.value) {
setScreenElements(screenVideoElement.value, screenCanvasElement.value)
}
}
// ============================================
// 4. Attach Screen Share
// ============================================
const withTimeout = <T>(p: Promise<T>, ms = 15000): Promise<T> => {
return new Promise<T>((resolve, reject) => {
const id: any = setTimeout(() => {
reject(new Error('startShareScreen: timeout'))
}, ms)
p.then((v) => {
clearTimeout(id)
resolve(v)
}).catch((e) => {
clearTimeout(id)
reject(e)
})
})
}
const attachScreen = async (userId?: number) => {
let userIdentity: number
if (userId) {
userIdentity = Number(zoomClient.getUser(userId)?.userIdentity)
} else {
userIdentity = Number(zoomClient.getCurrentUserInfo().userIdentity)
userId = zoomClient.getCurrentUserInfo().userId
}
// Short circuit if user id or zoom is undefined
if (!userId || !userIdentity || !zoomSession) {
return
}
// SELF SCREEN SHARE
if (userId === zoomClient.getCurrentUserInfo().userId) {
const element = isStartShareScreenWithVideoElement.value
? getScreenVideoElement()
: getScreenCanvasElement()
// Validate that the element is properly mounted before starting screen share
if (!element) {
showZoomErrorMessage(
new Error('Screen share is not yet ready. Please try again.'),
'attachScreen1'
)
return
}
const options = {
...(!zoomSession.isSupportMicrophoneAndShareAudioSimultaneously() && {
hideShareAudioOption: true,
}),
}
isShareScreenLoading.value = true
try {
await withTimeout(zoomSession.startShareScreen(element, options))
isShareScreenLoading.value = false
isShareScreenWithVideoElement.value = isStartShareScreenWithVideoElement.value
} catch (error) {
showZoomErrorMessage(error, 'attachScreen1')
}
}
// VIEWING OTHER'S SCREEN SHARE
else {
isShareScreenWithVideoElement.value = false
const screenElement = getScreenCanvasElement()
// Validate that the screen canvas element exists
if (!screenElement) {
showZoomErrorMessage(
new Error('Screen share is not yet ready. Please try again.'),
'attachScreen2'
)
return
}
isShareScreenLoading.value = true
try {
await zoomSession.startShareView(screenElement, userId)
isShareScreenLoading.value = false
zoomSession.updateSharedVideoQuality(VideoQuality.Video_1080P)
} catch (error) {
showZoomErrorMessage(error, 'attachScreen2')
}
}
// Subscribe to share statistics
zoomSession.subscribeShareStatisticData()
setIsUserScreenSharing(true)
}
// ============================================
// 5. Detach Screen Share
// ============================================
const detachScreen = async (userId?: number) => {
if (userId === undefined) {
userId = zoomClient.getCurrentUserInfo()?.userId
}
if (userId) {
if (userId === zoomClient.getCurrentUserInfo()?.userId) {
isShareScreenLoading.value = true
try {
await zoomSession.stopShareScreen()
isShareScreenLoading.value = false
} catch (error) {
showZoomErrorMessage(error, 'detachScreen1')
}
} else {
try {
await zoomSession.stopShareView()
isShareScreenLoading.value = false
} catch (error) {
showZoomErrorMessage(error, 'detachScreen2')
}
}
// Unsubscribe from share statistics
zoomSession.unsubscribeShareStatisticData()
setIsUserScreenSharing(false)
}
}
// ============================================
// 6. Public API Methods
// ============================================
const shareScreen = async () => {
if (zoomSession) {
const status = zoomSession.getShareStatus()
if (status !== ShareStatus.End) {
await stopShareScreen()
}
try {
// Ensure screen elements exist before attempting to share
const needsVideoElement = isStartShareScreenWithVideoElement.value
const requiredElement = needsVideoElement
? getScreenVideoElement()
: getScreenCanvasElement()
if (!requiredElement) {
throw new Error('Screen share is not yet ready. Please try again.')
}
await attachScreen()
setIsScreenSharing(true)
} catch (error) {
setIsScreenSharing(false)
setShareScreen(false)
showZoomErrorMessage(error, 'shareScreen')
}
}
}
const stopShareScreen = async () => {
if (zoomSession) {
await detachScreen()
await delay(200)
setIsScreenSharing(false)
}
}
// ============================================
// 7. Event Listeners
// ============================================
const onPassivelyStopShare = async (event: PassiveStopShareReason) => {
console.warn('[share] passively stopped by SDK event', {
time: new Date().toISOString(),
event,
})
isShareScreenLoading.value = true
await delay(700)
setIsUserScreenSharing(false)
setIsScreenSharing(false)
await nextTick()
isShareScreenLoading.value = false
}
const onActiveShareChanged = async (payload: {
state: ShareStateType
userId: number
}) => {
const { state, userId } = payload
console.info('[share] active-share-change', { state, userId })
if (state === ShareStateType.ACTIVE) {
attachScreen(userId)
} else if (state === ShareStateType.INACTIVE) {
detachScreen(userId)
}
}
// Register events
client.on('passively-stop-share', onPassivelyStopShare)
client.on('active-share-change', onActiveShareChanged)
// ============================================
// 8. HTML Template (Vue 3)
// ============================================
/*
<video-player-container>
<div
v-show="isScreenShared"
ref="screenShareElement"
class="Caller-screen Caller-screenView"
:style="screenShareStyles"
>
<div class="Caller-video" @dblclick="toggleFullscreen()">
<!-- Video element for video-based screen sharing -->
<video
v-if="!isScreenReset"
v-show="isShareScreenWithVideoElement"
ref="screenVideoElement"
class="Caller-videoScreenView"
muted
/>
<!-- Canvas element for canvas-based screen sharing -->
<canvas
v-if="!isScreenReset"
v-show="!isShareScreenWithVideoElement"
ref="screenCanvasElement"
class="Caller-videoScreenView"
/>
</div>
</div>
<video-player-container>
*/
// ============================================
// 9. Watcher for Screen Share State
// ============================================
watch(isScreenShared, (value) => {
if (!value) {
resetScreenElements()
syncParticipants()
}
if (value && call?.value?.id) {
const changeableViews = [ChatCallVideoTypeView.GRID]
if (changeableViews.includes(videoCallView.value)) {
changeVideoCallView({
callId: call.value.id,
view: ChatCallVideoTypeView.CONTENT,
})
}
}
})
// ============================================
// 10. Key Configuration
// ============================================
const isSABEnabled = computed(
() => typeof SharedArrayBuffer === 'function' && window.crossOriginIsolated
)
const isStartShareScreenWithVideoElement = computed(() => {
return zoomSession?.isStartShareScreenWithVideoElement()
})
// SDK Initialization
const payload: InitOptions = {
patchJsMedia: true,
stayAwake: true,
enforceMultipleVideos: !isSABEnabled.value,
leaveOnPageUnload: true,
}
await zoomClient.init('en-US', 'Global', payload)
vic.yang
(Vic)
February 27, 2026, 7:54am
4
Hi @matthew.offshorly
9UY6cvowTxWQOwo89GZhlw==
After analyzing the logs, we identified some issues. I’d like to understand whether a new canvas element is created each time stream.startShareView or stream.startShareScreen is called.
Our screen share content is rendered on the WebGL context. Due to browser limitations, there is a limit to the number of WebGL contexts that can be created on the same page. Exceeding this limit will prevent rendering on them.
Therefore, if possible, please hide the element using CSS instead of constructing and destructing it repeatedly.
Thanks
Vic
Hi @vic.yang tried to use css when hiding screen element, instead of constructing and destructing it repeatedly, although after a switching share screen between users, startShareView times out
Session ID:mB30k7RHReSn7TLnucmV+A==
Steps to replicate:
User 1 starts share screen then stops share screen using browser control
User 2 starts share screen then screen doesn’t appear for User 1
Then this error appears for User 1
zoomSession.startShareView(canvasElement, userId)
{"type":"OPERATION_TIMEOUT","errorCode":1}
Hi @matthew.offshorly
mB30k7RHReSn7TLnucmV+A==
After analyzing the log, we found the the canvas is used by both stream. startShareScreen and stream.startShareView methods.
Currently, due to technical limitations, the self share view and the remote share view cannot use the same canvas. Could you try using different canvases and, when screen sharing stops, keep the canvas element and only hide it using CSS?
Thanks
Vic