GitbookIO/gitbook · error · Error
Iframe must have a content window
Error message
Iframe must have a content window
What it means
Thrown by createGitBookFrame in @gitbook/embed when the passed HTMLIFrameElement has no contentWindow. An iframe only gets its content window once it has been inserted into the document and its browsing context has been created, so calling this before mounting (or on a detached element) always fails. The client needs the window to set up postMessage communication with the embedded GitBook frame.
Source
Thrown at packages/embed/src/client/createGitBookFrame.ts:51
clearChat: () => void;
/**
* Set the placeholder settings.
*/
configure: (settings: Partial<GitBookEmbeddableConfiguration>) => void;
/**
* Register an event listener.
*/
on: (event: string, listener: (...args: any[]) => void) => () => void;
};
/**
* Create a client to communicate with the GitBook Assistant frame.
*/
export function createGitBookFrame(iframe: HTMLIFrameElement): GitBookFrameClient {
if (!iframe.contentWindow) {
throw new Error('Iframe must have a content window');
}
const allowTokens = iframe.allow
.split(';')
.map((token) => token.trim())
.filter(Boolean);
if (!allowTokens.includes('clipboard-write')) {
iframe.allow = [...allowTokens, 'clipboard-write'].join('; ');
}
const channel = createChannel(iframe.contentWindow);
channel.receive((message: FrameToParentMessage) => {
console.log('[gitbook:embed] received message', message);
if (message.type === 'close') {
const listeners = events.get('close') || [];
if (listeners) {View on GitHub (pinned to db67585ee2)
Solutions
- Call createGitBookFrame inside useEffect (or after the iframe's load event) so the element is mounted and contentWindow exists
- If using a manual iframe, append it to the document before creating the frame client
- Guard with a check: only create the client when iframe.contentWindow is truthy
Example fix
// before
const client = createGitBookFrame(ref.current); // during render / unmounted
// after
useEffect(() => {
if (!ref.current?.contentWindow) return;
const client = createGitBookFrame(ref.current);
}, []); Defensive patterns
Strategy: type-guard
Type guard
function hasContentWindow(iframe: HTMLIFrameElement | null): iframe is HTMLIFrameElement & { contentWindow: Window } {
return !!iframe?.contentWindow;
} Prevention
- Create the frame client inside useEffect after mount
- Wait for the iframe's load event before initializing
- Never call createGitBookFrame on a detached createElement'd iframe
When it happens
Trigger: Calling createGitBookFrame(iframe) inside useEffect before the iframe is appended to the DOM; using a ref whose current is null or whose element was created with document.createElement but never attached; calling it during render instead of in an effect after mount.
Common situations: React integration where createGitBookFrame is called too early (during render or in a ref callback that fires before insertion); testing with jsdom where contentWindow can be null; manually constructing the iframe and forgetting document.body.appendChild; the iframe was removed from the DOM before the call.
Related errors
AI-assisted analysis of GitbookIO/gitbook@db67585ee2 (2026-08-28).
Data as JSON: /api/errors/41fc5cd1e6eb23f8.
Report an issue: GitHub.