toeverything/AFFiNE · warning · BlockSuiteError
EdgelessExportError
EdgelessExportError
Error message
Unable to export content to canvas
What it means
Thrown by ExportManager._checkCanContinueToCanvas (the surface block's export manager) under the same conditions as the clipboard variant [11]: location.pathname changed or isInsidePageEditor(editorHost) flipped between the start of the export and a continuation check. Error code EdgelessExportError (a structured BlockSuiteError, unlike [11]'s plain Error). It is polled inside _checkReady's interval and rejects the readiness promise on change.
Source
Thrown at blocksuite/affine/blocks/surface/src/extensions/export-manager/export-manager.ts:112
await Promise.all(promises);
};
get doc(): Store {
return this.std.store;
}
get editorHost(): EditorHost {
return this.std.host;
}
constructor(readonly std: BlockStdScope) {}
private _checkCanContinueToCanvas(pathName: string, editorMode: boolean) {
if (
location.pathname !== pathName ||
isInsidePageEditor(this.editorHost) !== editorMode
) {
throw new BlockSuiteError(
ErrorCode.EdgelessExportError,
'Unable to export content to canvas'
);
}
}
private async _checkReady() {
const pathname = location.pathname;
const editorMode = isInsidePageEditor(this.editorHost);
const promise = new Promise((resolve, reject) => {
let count = 0;
const checkReactRender = setInterval(() => {
try {
this._checkCanContinueToCanvas(pathname, editorMode);
} catch (e) {
clearInterval(checkReactRender);
reject(e);View on GitHub (pinned to 26c515e050)
Solutions
- Await the export promise and prevent route/mode changes until it resolves (disable the toggle, lock navigation).
- Catch BlockSuiteError with code EdgelessExportError at the call site and treat it as cancellation, not a fatal fault.
- Reduce export bound / pre-render off-screen blocks to shorten the window in which navigation can invalidate the export.
Example fix
// before
await exportManager.edgelessToCanvas(bound); // throws if user navigates
// after
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
try {
await exportManager.edgelessToCanvas(bound);
} catch (e) {
if (e instanceof BlockSuiteError && e.code === ErrorCode.EdgelessExportError) {
notify('Export cancelled: view changed.');
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// prevent navigation/mode changes during export const pathName = location.pathname; const editorMode = isInsidePageEditor(editorHost); setNavigationLocked(true); await exportManager.edgelessToCanvas(bound); setNavigationLocked(false);
Try / catch
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
try { await exportManager.edgelessToCanvas(bound); }
catch (e) {
if (e instanceof BlockSuiteError && e.code === ErrorCode.EdgelessExportError) {
// cancellation: view changed mid-export
} else throw e;
} Prevention
- Lock navigation and mode toggles while an export is in flight.
- Await the export promise before releasing the lock.
- Treat EdgelessExportError from the readiness check as cancellation.
When it happens
Trigger: Calling ExportManager.docToCanvas/edgelessToCanvas and navigating to a different route or toggling page/edgeless mode while the readiness interval (10s window, 100ms ticks) or the html2canvas pipeline is still running. Also triggered if the SPA route changes for any reason mid-export.
Common situations: Long exports on heavy docs where the user navigates away; automated exports run concurrently with other code that mutates the route; browser back/forward during export; mode-toggle shortcuts pressed during export.
Related errors
- Unable to export content to canvas
- EdgelessExportError
- GfxBlockElementError
- NoSurfaceModelError
- MissingViewModelError
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/84348b057f31d0f0.
Report an issue: GitHub.