toeverything/AFFiNE · error · BlockSuiteError
EdgelessExportError
EdgelessExportError
Error message
Unable to export content to canvas
What it means
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.
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)
Example fix
// before
const t = db.table('usres'); // typo -> Table not found
// after
const TABLES = { users: usersSchema, docs: docsSchema } as const; // single source of truth
const db = new YjsDBAdapter(TABLES, docProvider);
const t = db.table('users'); Defensive patterns
Strategy: validation
Validate before calling
function getTable(db: YjsDBAdapter, name: string) {
if (!db.tables.has(name)) {
throw new Error(`Table '${name}' not declared in schema. Declared: ${[...db.tables.keys()].join(', ')}`);
}
return db.table(name);
} Type guard
null
Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- [Table( )]: Field ' ' can't be marked primary key and…
- [Table( )]: Field ' ' is reserved keyword and can't be used.
- [Table( )]: Field ' ' is reserved keyword and can't be set.
- [Table( )]: There should be at least one field marked as…
- [Table( )]: There should be only one field marked as…
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/84348b057f31d0f0.
Report an issue: GitHub.
Appendix: 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 b4c8548c09)