{"record":{"id":"84348b057f31d0f0","repo":"toeverything/AFFiNE","slug":"edgelessexporterror-84348b","errorCode":"EdgelessExportError","errorMessage":"Unable to export content to canvas","messagePattern":"Unable to export content to canvas","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"error","filePath":"blocksuite/affine/blocks/surface/src/extensions/export-manager/export-manager.ts","lineNumber":112,"sourceCode":"    await Promise.all(promises);\n  };\n\n  get doc(): Store {\n    return this.std.store;\n  }\n\n  get editorHost(): EditorHost {\n    return this.std.host;\n  }\n\n  constructor(readonly std: BlockStdScope) {}\n\n  private _checkCanContinueToCanvas(pathName: string, editorMode: boolean) {\n    if (\n      location.pathname !== pathName ||\n      isInsidePageEditor(this.editorHost) !== editorMode\n    ) {\n      throw new BlockSuiteError(\n        ErrorCode.EdgelessExportError,\n        'Unable to export content to canvas'\n      );\n    }\n  }\n\n  private async _checkReady() {\n    const pathname = location.pathname;\n    const editorMode = isInsidePageEditor(this.editorHost);\n\n    const promise = new Promise((resolve, reject) => {\n      let count = 0;\n      const checkReactRender = setInterval(() => {\n        try {\n          this._checkCanContinueToCanvas(pathname, editorMode);\n        } catch (e) {\n          clearInterval(checkReactRender);\n          reject(e);","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/affine/blocks/surface/src/extensions/export-manager/export-manager.ts#L94-L130","documentation":"YjsDBAdapter builds its table map exactly once, in the constructor, from the schema object passed in — creating one Yjs doc per declared table. table(name) looks up that prebuilt map and throws the bare 'Table not found' when the name was never declared, because there is no Yjs doc backing an undeclared table.","triggerScenarios":"Calling db.table('usres') with a typo; accessing a table present in a different or newer schema than the one the adapter was constructed with; a schema migration renamed the table while callers kept the old name; constructing the adapter from an empty/partial schema object.","commonSituations":"Version skew between the schema definition and consuming code; table names assembled dynamically from strings that drift from declarations; adapter instantiated before the schema module populates its definitions.","solutions":["Declare the table in the DB schema builder passed to YjsDBAdapter so a doc is created for it","Fix the name at the call site; centralize table names as constants shared with the schema definition","For dynamic access, check the public tables map first: db.tables.has(name)"],"exampleFix":"// before\nconst t = db.table('usres'); // typo -> Table not found\n\n// after\nconst TABLES = { users: usersSchema, docs: docsSchema } as const; // single source of truth\nconst db = new YjsDBAdapter(TABLES, docProvider);\nconst t = db.table('users');","handlingStrategy":"validation","validationCode":"function getTable(db: YjsDBAdapter, name: string) {\n  if (!db.tables.has(name)) {\n    throw new Error(`Table '${name}' not declared in schema. Declared: ${[...db.tables.keys()].join(', ')}`);\n  }\n  return db.table(name);\n}","typeGuard":"null","tryCatchPattern":null,"preventionTips":["Centralize table names as constants shared by schema definition and callers","Construct the adapter from the complete schema before serving table() calls","Use db.tables.has(name) for dynamic/interpolated table names"],"tags":["orm","yjs","table","schema","typo"],"backgroundTag":"missing-table-schema","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"}