{"record":{"id":"6c8b7312c3c8e08d","repo":"toeverything/AFFiNE","slug":"errorcode-modelcruderror-6c8b73","errorCode":"ErrorCode.ModelCRUDError","errorMessage":"schema for flavour: ${flavour} not found","messagePattern":"schema for flavour: (.+?) not found","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"error","filePath":"blocksuite/framework/store/src/model/store/crud.ts","lineNumber":55,"sourceCode":"    if (!parent) return null;\n\n    const children = parent.get('sys:children');\n    const index = children.toArray().indexOf(id);\n    if (index === -1) return null;\n\n    return fn(index, parent);\n  }\n\n  addBlock(\n    id: string,\n    flavour: string,\n    initialProps: Record<string, unknown> = {},\n    parent?: string | null,\n    parentIndex?: number\n  ) {\n    const schema = this._schema.flavourSchemaMap.get(flavour);\n    if (!schema) {\n      throw new BlockSuiteError(\n        ErrorCode.ModelCRUDError,\n        `schema for flavour: ${flavour} not found`\n      );\n    }\n\n    const hasBlock = this._yBlocks.has(id);\n    if (hasBlock) {\n      throw new BlockSuiteError(\n        ErrorCode.ModelCRUDError,\n        `Should not add existing block: ${id}`\n      );\n    }\n\n    const parentFlavour = parent\n      ? this._yBlocks.get(parent)?.get('sys:flavour')\n      : undefined;\n\n    this._schema.validate(flavour, parentFlavour as string);","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/framework/store/src/model/store/crud.ts#L37-L73","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ndoc.addBlock('affine:paragarph', { type: 'text' }, parentId); // typo -> throws\n\n// after\nimport { ParagraphBlock } from 'affine/blocks';\ndoc.schema.register([ParagraphBlock]);\ndoc.addBlock('affine:paragraph', { type: 'text' }, parentId);","handlingStrategy":"validation","validationCode":"if (doc.schema.flavourSchemaMap.has(flavour)) {\n  doc.addBlock(flavour, props, parentId);\n} else {\n  doc.schema.register([MissingBlock]);\n  doc.addBlock(flavour, props, parentId);\n}","typeGuard":"const canAddFlavour = (doc: Store, flavour: string): boolean =>\n  doc.schema.flavourSchemaMap.has(flavour);","tryCatchPattern":"try {\n  doc.addBlock(flavour, props, parentId);\n} catch (e) {\n  if (e instanceof BlockSuiteError && e.code === ErrorCode.ModelCRUDError) {\n    // most likely a typo: compare flavour against schema.flavourSchemaMap keys\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["blocksuite","schema","flavour","addblock","registration"],"backgroundTag":"missing-schema-registration","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"}