Observed behaviour
In the web app, clicking Pop-out call while in a voice call / watching a screenshare briefly opens a new popup window and then immediately closes it again.
Expected behaviour:
The popup window should remain open and render the call/stream.
The issue is reproducible on the same self-hosted Fluxer instance in multiple browser/OS combinations:
- Firefox on Linux
- Chrome on Windows
window.open() twice for the same named popup target (fluxer-voice-popout:call:<channelId>).
If I intercept only the second window.open() call and return the already existing popup window instead, the pop-out remains open and works correctly.
The same workaround fixes the issue in both Firefox/Linux and Chrome/Windows.
No interception of window.close() or other browser behaviour is required for the workaround.Reproduction steps
- Open the self-hosted Fluxer instance in a web browser.
- Join a voice channel / call.
- Open a screenshare or call view.
- Click Pop-out call in the bottom-right corner.
- Observe that a popup window appears briefly and then immediately closes.
Build information
Stable Web 2026.920.41245, Linux (x64), Firefox 156.0, Locale en-US
Platform
Web
Instance
Self-hosted, v1, PostgreSQL, Docker
Evidence
The current browser pop-out implementation appears to open the same named window twice.
The effect cleanup then closes the child window:
PopoutWindowManager.ts opens the browser window when registering the pop-out:
const childWindow = window . open (
'about:blank' ,
descriptor . key ,
`width= ${ width } ,height= ${ height } ` ,
); PopoutWindow.tsx then calls window.open() again using the same windowKey:
const features = `width= ${ initialSizeRef . current . width } ,height= ${ initialSizeRef . current . height } ` ;
const childWindow = window . open ( 'about:blank' , windowKey , features ); PopoutWindow.tsx also registers a pagehide handler which calls onClosed():
const handlePageHide = () : void => {
if ( closed ) return ;
closed = true ;
onClosedRef . current ( windowGeneration );
};
childWindow . addEventListener ( 'pagehide' , handlePageHide ); return () => {
disconnectThemeObserver ();
disconnectStylesheetObserver ();
childWindow . removeEventListener ( 'pagehide' , handlePageHide );
closed = true ;
if ( ! childWindow . closed ) {
childWindow . close ();
}
}; Details
Observed call sequence
While debugging in Firefox, I instrumentedwindow.open() in the main Fluxer window.
Two calls to window.open() are made for the same named target, similar to:
window.open(
"about:blank",
"fluxer-voice-popout:call:<channelId>",
"width=960,height=600"
)
PopoutWindow.tsx
VoicePopoutHost.tsx
Working diagnostic workaround
To test whether the secondwindow.open() call is involved, I intercepted only subsequent calls for an already-open fluxer-voice-popout:* target and returned the existing window instead:
(() => {
const originalOpen = window . open . bind ( window );
const popouts = new Map ();
window . open = ( url , target , features ) => {
if (
typeof target === "string" &&
target . startsWith ( "fluxer-voice-popout:" )
) {
const existing = popouts . get ( target );
if ( existing && ! existing . closed ) {
return existing ;
}
const popup = originalOpen ( url , target , features );
if ( popup ) {
popouts . set ( target , popup );
}
return popup ;
}
return originalOpen ( url , target , features );
};
})(); window.close() or other browser behaviour is required for the workaround.
Likely cause
The issue appears to be related to the pop-out lifecycle and the secondwindow.open('about:blank', ...) call for the same named target.
This is not Firefox-specific: the same behaviour is reproducible in Chrome on Windows.
In both tested environments, intercepting the second window.open() call and returning the already existing Window object makes the pop-out work normally.
The exact reason why the second call causes the pop-out lifecycle to be torn down has not been determined yet.
2 comments
Comment by @SolunaCG
window.open()workaround fixes it there as well. I updated the title, reproduction details and evidence accordingly.Comment by @omstr