{"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":null,"httpStatus":null,"severity":"critical","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/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/affine/blocks/root/src/edgeless/clipboard/clipboard.ts#L409-L445","documentation":"Before running a factory, Resolver.track checks whether the requested identifier (name+variant) already appears on the current resolution stack; if so, the container throws CircularDependencyError with the full cycle printed as [A] -> [B] -> ... -> [A]. This detects constructor-level dependency cycles at resolve time instead of leaking half-built instances or overflowing the JS stack.","triggerScenarios":"framework.service(A, [B]) and framework.service(B, [A]); a component that (directly or through a variant) injects itself; cycles that cross scopes and are resolved with sameScope chains.","commonSituations":"Two services that naturally reference each other (editor <-> document, auth <-> router); a refactor that adds a dependency and accidentally closes a loop; entity hierarchies with parent back-references injected via constructor.","solutions":["Break the cycle by resolving the back-reference lazily: inject the provider/resolver and call get(...) inside methods, not in the constructor/deps array","Extract the functionality both sides need into a third component that both depend on instead of on each other","Use the printed dependency stack to find the exact pair, remove one edge; for notification-style coupling use eventBus instead of direct injection"],"exampleFix":"// before\nfw.service(Editor, [Document]);\nfw.service(Document, [Editor]); // CircularDependencyError: [Editor] -> [Document] -> [Editor]\n\n// after\nfw.service(Document, []);\nfw.service(Editor, [Document]); // one direction only; use eventBus for the way back","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"import { CircularDependencyError } from '.../framework/core/error';\n\ntry {\n  provider.get(Editor);\n} catch (err) {\n  if (err instanceof CircularDependencyError) {\n    // err.dependencyStack prints the exact cycle; break one edge in the graph\n  } else {\n    throw err;\n  }\n}","preventionTips":["Inject one direction of a mutual relationship; obtain the other lazily via the resolver inside methods","Use the eventBus for back-notification instead of constructor injection","Extract shared logic into a third component both sides depend on"],"tags":["dependency-injection","circular-dependency","resolution"],"backgroundTag":"circular-dependency","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}