TanStack/query · warning · PipOpenError
Failed to open popup. Please allow popups for this site to v
Error message
Failed to open popup. Please allow popups for this site to view the devtools in picture-in-picture mode.
What it means
Thrown as `PipOpenError` from the devtools `PiPProvider` when `window.open(..., 'popup')` returns `null` — i.e. the browser blocked the popup. The devtools picture-in-picture mode is implemented via a real popup window (a fallback before the native Document Picture-in-Picture API), so it depends on the user granting popup permission for the origin. The provider catches this specific error in its `createEffect` and downgrades gracefully (logs the message, resets `pip_open`/`open` flags), but if you call `requestPipWindow` directly it propagates to you.
Source
Thrown at packages/query-devtools/src/contexts/PiPContext.tsx:63
setPipWindow(null)
}
}
// Open new pipWindow
const requestPipWindow = (width: number, height: number) => {
// We don't want to allow multiple requests.
if (pipWindow() != null) {
return
}
const pip = window.open(
'',
'TSQD-Devtools-Panel',
`width=${width},height=${height},popup`,
)
if (!pip) {
throw new PipOpenError(
'Failed to open popup. Please allow popups for this site to view the devtools in picture-in-picture mode.',
)
}
// Remove existing styles
pip.document.head.innerHTML = ''
// Remove existing body
pip.document.body.innerHTML = ''
// Clear Delegated Events
clearDelegatedEvents(pip.document)
pip.document.title = 'TanStack Query Devtools'
pip.document.body.style.margin = '0'
// Detect when window is closed by user
pip.addEventListener('pagehide', () => {
props.setLocalStore('pip_open', 'false')
setPipWindow(null)View on GitHub (pinned to 159982c80b)
Solutions
- Tell the user to allow popups for the site (browser site settings -> Pop-ups and redirects -> Allow), then click the PiP toggle again.
- Ensure `requestPipWindow` is only invoked from a user-gesture handler (click/keydown), not from an effect or timer.
- If embedding in an iframe, add `allow="popups"` (and ideally `allow="popups; picture-in-picture"`) to the iframe element.
- In tests, grant the popup permission in the browser context, e.g. Playwright `context.grantPermissions(['popup'])` or launch with `--disable-popup-blocking`.
Example fix
// before - iframe blocks the devtools popup <iframe src="/devtools" sandbox="allow-scripts"></iframe> // after - allow popups in the sandbox <iframe src="/devtools" sandbox="allow-scripts allow-popups"></iframe>
Defensive patterns
Strategy: try-catch
Validate before calling
// Check before requesting the PiP popup
const canOpenPopup = () => {
try {
const w = window.open('', '__popup_test__', 'width=1,height=1')
if (w) { w.close(); return true }
return false
} catch {
return false
}
}
// Note: probing has side effects and may itself be blocked; prefer feature-detecting on user gesture. Type guard
// Feature-detect popup support (best effort) const supportsPopups = () => typeof window !== 'undefined' && typeof window.open === 'function'
Try / catch
try {
requestPipWindow(width, height)
} catch (e) {
if (e.message.startsWith('Failed to open popup')) {
// inform the user to allow popups, do not crash
setShowPipBlockedMessage(true)
} else {
throw e
}
} Prevention
- Only trigger PiP from a user-gesture handler (click/keydown), never from an effect or setTimeout.
- If running in an iframe, add allow="popups; picture-in-picture" to the iframe sandbox.
- In E2E tests, launch the browser with --disable-popup-blocking or grant the popup permission.
- Surface a friendly UI fallback (e.g. 'Please allow popups') when the error fires.
When it happens
Trigger: User clicks the PiP toggle while the browser blocks popups for the site; popup blocker extension active; `window.open` called outside a user-gesture transient activation (e.g. programmatically on mount, or in a `setTimeout`); embedded in an iframe without `allow-popups` in the sandbox attribute; headless / test environment where `window.open` is unavailable.
Common situations: Default Chrome/Edge blocking popups on an unfamiliar origin; embedded devtools in a sandboxed iframe (Storybook, CodeSandbox, StackBlitz); CI / end-to-end test runs (Playwright, Puppeteer) where popups are blocked; calling `requestPipWindow` from a non-interactive context.
Related errors
- usePiPWindow must be used within a PiPProvider
- No QueryClient found
- No QueryClient found
- Devtools is already mounted
- Devtools is not mounted
AI-assisted analysis of TanStack/query@159982c80b (2026-08-12).
Data as JSON: /api/errors/83530e11be927fc3.
Report an issue: GitHub.