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

  1. Register the block schema(s) with schema.register([...]) before the first addBlock call
  2. Double-check the flavour string against the defineBlockSchema declaration (e.g. 'affine:paragraph' vs 'affine:paragraphh')
  3. Use the exported schema object/constant instead of a hand-typed string literal
  4. 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

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


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)