RocketChat/Rocket.Chat · error · Error

Could not open popup

Error message

Could not open popup

What it means

Thrown by the CAS login popup helper when window.open() returns null. Browsers return null from window.open when a popup blocker prevents the new window from being created. This function orchestrates the CAS (Central Authentication Service) single sign-on flow by opening a centered popup window for the CAS login URL.

Source

Thrown at apps/meteor/client/lib/openCASLoginPopup.ts:20

import { getRootUrlPathPrefix } from './meteorRuntimeConfig';
import { settings } from './settings';

const openCenteredPopup = (url: string, width: number, height: number) => {
	const screenX = window.screenX ?? window.screenLeft;
	const screenY = window.screenY ?? window.screenTop;
	const outerWidth = window.outerWidth ?? document.body.clientWidth;
	const outerHeight = window.outerHeight ?? document.body.clientHeight - 22;
	// XXX what is the 22? Probably the height of the title bar.
	// Use `outerWidth - width` and `outerHeight - height` for help in
	// positioning the popup centered relative to the current window
	const left = screenX + (outerWidth - width) / 2;
	const top = screenY + (outerHeight - height) / 2;
	const features = `width=${width},height=${height},left=${left},top=${top},scrollbars=yes`;

	const newwindow = window.open(url, 'Login', features);

	if (!newwindow) {
		throw new Error('Could not open popup');
	}

	newwindow.focus();

	return newwindow;
};

const getPopupUrl = (credentialToken: string): string => {
	const loginUrl = settings.peek<string | undefined>('CAS_login_url');

	if (!loginUrl) {
		throw new Error('CAS_login_url not set');
	}

	const appUrl = absoluteUrl().replace(/\/$/, '') + getRootUrlPathPrefix();
	const serviceUrl = `${appUrl}/_cas/${credentialToken}`;
	const url = new URL(loginUrl);
	url.searchParams.set('service', serviceUrl);

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Ensure window.open is called synchronously within a user-initiated event handler (click, tap).
  2. Prompt the user to disable popup blocking for this site if the popup fails to open.
  3. Catch the error and show a fallback message with a direct link the user can click manually.
  4. Use a redirect-based CAS flow instead of a popup if popups are consistently blocked.

Example fix

// before
const popup = openCASLoginPopup(token); // may be outside click handler
// after
// In a click handler:
button.onclick = () => {
  try {
    const popup = openCASLoginPopup(token);
  } catch {
    showPopupBlockedMessage();
  }
};
Defensive patterns

Strategy: try-catch

Validate before calling

if (typeof window === 'undefined' || !window.open) {
  throw new Error('Popups not supported in this environment');
}
// ensure called within a user gesture
const popup = openCASLoginPopup(token);

Type guard

const canOpenPopup = (): boolean =>
  typeof window !== 'undefined' && typeof window.open === 'function';

Try / catch

try {
  const popup = openCASLoginPopup(token);
} catch (e) {
  if (e instanceof Error && e.message === 'Could not open popup') {
    showPopupBlockedGuidance();
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: The browser's built-in popup blocker is enabled and blocks the window.open call. A browser extension (ad blocker, privacy extension) blocks popups. window.open is called outside a direct user gesture (some browsers block programmatic popups not triggered by user clicks). Corporate browser policy disables popups.

Common situations: User has a popup blocker extension installed. The CAS login is triggered programmatically (e.g., on page load or via a timer) instead of from a click handler. Chrome/Firefox/Safari popup blocker settings are at their default (which blocks non-user-initiated popups). Enterprise managed browsers with strict popup policies.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/f3a357d2157716e4. Report an issue: GitHub.