{"record":{"id":"d6178f25afaac292","repo":"toeverything/AFFiNE","slug":"unable-to-export-content-to-canvas","errorCode":null,"errorMessage":"Unable to export content to canvas","messagePattern":"Unable to export content to canvas","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"blocksuite/affine/blocks/root/src/edgeless/clipboard/clipboard.ts","lineNumber":427,"sourceCode":"\n  private get crud() {\n    return this.std.get(EdgelessCRUDIdentifier);\n  }\n\n  private get toolManager() {\n    return this.gfx.tool;\n  }\n\n  private _checkCanContinueToCanvas(\n    host: EditorHost,\n    pathName: string,\n    editorMode: boolean\n  ) {\n    if (\n      location.pathname !== pathName ||\n      isInsidePageEditor(host) !== editorMode\n    ) {\n      throw new Error('Unable to export content to canvas');\n    }\n  }\n\n  private async _edgelessToCanvas(\n    bound: IBound,\n    nodes?: GfxBlockElementModel[],\n    canvasElements: GfxPrimitiveElementModel[] = [],\n    {\n      background,\n      padding = IMAGE_PADDING,\n      dpr = window.devicePixelRatio || 1,\n    }: CanvasExportOptions = {}\n  ): Promise<HTMLCanvasElement | undefined> {\n    const host = this.std.host;\n    const rootModel = this.doc.root;\n    if (!rootModel) return;\n\n    const html2canvas = (await import('html2canvas')).default;","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/blocksuite/affine/blocks/root/src/edgeless/clipboard/clipboard.ts#L409-L445","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntry { await clipboardToCanvas(...); } catch (e) { /* unhandled */ }\n\n// after\ntry {\n  await clipboardToCanvas(...);\n} catch (e) {\n  if (e instanceof Error && /export content to canvas/.test(e.message)) {\n    notify('Export cancelled: the view changed.');\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"// capture navigation state and lock UI during export\nconst pathName = location.pathname;\nconst editorMode = isInsidePageEditor(host);\n// disable navigation/mode toggle while exporting\nawait exportPromise;","typeGuard":null,"tryCatchPattern":"try { await clipboardToCanvas(...); }\ncatch (e) {\n  if (e instanceof Error && /export content to canvas/.test(e.message)) {\n    // treat as cancellation, not a fault\n  } else throw e;\n}","preventionTips":["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."],"tags":["edgeless","export","navigation-guard","async-cancel"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}