toeverything/AFFiNE · warning · Error
Unable to export content to canvas
Error message
Unable to export content to canvas
What it means
Thrown by EdgelessClipboardController._checkCanContinueToCanvas when, partway through an async canvas export, location.pathname no longer equals the pathName captured at the start, OR isInsidePageEditor(host) has flipped from the captured editorMode. It is a guard that aborts the expensive html2canvas pipeline if the user navigated away or switched between page/edgeless modes during the export. A plain Error.
Source
Thrown at blocksuite/affine/blocks/root/src/edgeless/clipboard/clipboard.ts:427
private get crud() {
return this.std.get(EdgelessCRUDIdentifier);
}
private get toolManager() {
return this.gfx.tool;
}
private _checkCanContinueToCanvas(
host: EditorHost,
pathName: string,
editorMode: boolean
) {
if (
location.pathname !== pathName ||
isInsidePageEditor(host) !== editorMode
) {
throw new Error('Unable to export content to canvas');
}
}
private async _edgelessToCanvas(
bound: IBound,
nodes?: GfxBlockElementModel[],
canvasElements: GfxPrimitiveElementModel[] = [],
{
background,
padding = IMAGE_PADDING,
dpr = window.devicePixelRatio || 1,
}: CanvasExportOptions = {}
): Promise<HTMLCanvasElement | undefined> {
const host = this.std.host;
const rootModel = this.doc.root;
if (!rootModel) return;
const html2canvas = (await import('html2canvas')).default;View on GitHub (pinned to 26c515e050)
Solutions
- Do not navigate or switch editor modes during an export; await the export promise before allowing route changes.
- Wrap the export call in try/catch and treat this error as a cancellation (not a fatal failure) — show a 'cancelled' message to the user.
- If exporting programmatically, lock navigation / disable the mode toggle until the promise resolves.
Example fix
// before
try { await clipboardToCanvas(...); } catch (e) { /* unhandled */ }
// after
try {
await clipboardToCanvas(...);
} catch (e) {
if (e instanceof Error && /export content to canvas/.test(e.message)) {
notify('Export cancelled: the view changed.');
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// capture navigation state and lock UI during export const pathName = location.pathname; const editorMode = isInsidePageEditor(host); // disable navigation/mode toggle while exporting await exportPromise;
Try / catch
try { await clipboardToCanvas(...); }
catch (e) {
if (e instanceof Error && /export content to canvas/.test(e.message)) {
// treat as cancellation, not a fault
} else throw e;
} Prevention
- Await the export promise before allowing navigation or mode switches.
- Lock the mode toggle / route changes during export.
- Treat this error as user-initiated cancellation.
When it happens
Trigger: Triggering an edgeless-to-canvas export (copy as image / export) and then navigating to another doc or toggling page-vs-edgeless mode before the async html2canvas pipeline completes. The check is re-evaluated at continuation points in _edgelessToCanvas.
Common situations: Slow exports on large canvases where the user clicks away; SPAs where route changes happen during export; programmatic exports invoked while other code mutates the route or mode.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/d6178f25afaac292.
Report an issue: GitHub.