toeverything/AFFiNE · error · BlockSuiteError
ErrorCode.ModelCRUDError
ErrorCode.ModelCRUDError
Error message
schema for flavour: ${flavour} not found What it means
Crud.addBlock resolves the flavour in the schema registry before creating any Yjs data, so calling Store.addBlock with a flavour string that has no registered schema fails fast with ModelCRUDError — nothing is written to the doc.
Solutions
- Register the block schema(s) with schema.register([...]) before the first addBlock call
- Double-check the flavour string against the defineBlockSchema declaration (e.g. 'affine:paragraph' vs 'affine:paragraphh')
- Use the exported schema object/constant instead of a hand-typed string literal
- Assert doc.schema.flavourSchemaMap.has(flavour) in dev builds
Example fix
// before
doc.addBlock('affine:paragarph', { type: 'text' }, parentId); // typo -> throws
// after
import { ParagraphBlock } from 'affine/blocks';
doc.schema.register([ParagraphBlock]);
doc.addBlock('affine:paragraph', { type: 'text' }, parentId); Defensive patterns
Strategy: validation
Validate before calling
if (doc.schema.flavourSchemaMap.has(flavour)) {
doc.addBlock(flavour, props, parentId);
} else {
doc.schema.register([MissingBlock]);
doc.addBlock(flavour, props, parentId);
} Type guard
const canAddFlavour = (doc: Store, flavour: string): boolean => doc.schema.flavourSchemaMap.has(flavour);
Try / catch
try {
doc.addBlock(flavour, props, parentId);
} catch (e) {
if (e instanceof BlockSuiteError && e.code === ErrorCode.ModelCRUDError) {
// most likely a typo: compare flavour against schema.flavourSchemaMap keys
}
throw e;
} Prevention
- Reference flavour constants exported from block modules instead of string literals
- Assert schema registration in dev builds before first addBlock
- Register schemas synchronously during app init, before any editor mounts
When it happens
Trigger: doc.addBlock('affine:paragraphh', {}, parent) with a typo; adding a custom block before schema.register ran; passing a flavour defined on a different Schema instance than the one the store uses.
Common situations: Typo'd flavour strings; schema registered asynchronously after the first render; copy-pasting flavour constants between packages that drift; using a bare `new Schema()` without registering presets.
Related errors
- ErrorCode.ModelCRUDError
- ErrorCode.ModelCRUDError
- Block cannot have parent
- Schema not found. The block flavour may not be registered.
- ErrorCode.ModelCRUDError
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/6c8b7312c3c8e08d.
Report an issue: GitHub.
Appendix: source
Thrown at blocksuite/framework/store/src/model/store/crud.ts:55
if (!parent) return null;
const children = parent.get('sys:children');
const index = children.toArray().indexOf(id);
if (index === -1) return null;
return fn(index, parent);
}
addBlock(
id: string,
flavour: string,
initialProps: Record<string, unknown> = {},
parent?: string | null,
parentIndex?: number
) {
const schema = this._schema.flavourSchemaMap.get(flavour);
if (!schema) {
throw new BlockSuiteError(
ErrorCode.ModelCRUDError,
`schema for flavour: ${flavour} not found`
);
}
const hasBlock = this._yBlocks.has(id);
if (hasBlock) {
throw new BlockSuiteError(
ErrorCode.ModelCRUDError,
`Should not add existing block: ${id}`
);
}
const parentFlavour = parent
? this._yBlocks.get(parent)?.get('sys:flavour')
: undefined;
this._schema.validate(flavour, parentFlavour as string);View on GitHub (pinned to b4c8548c09)