{"record":{"id":"d4e630593996c609","repo":"toeverything/AFFiNE","slug":"errorcode-modelcruderror-d4e630","errorCode":"ErrorCode.ModelCRUDError","errorMessage":"schema for flavour: ${this.flavour} not found","messagePattern":"schema for flavour: (.+?) not found","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"critical","filePath":"blocksuite/framework/store/src/model/block/sync-controller.ts","lineNumber":133,"sourceCode":"    readonly onChange?: (key: string, isLocal: boolean) => void\n  ) {\n    const { id, flavour, version, yChildren, props } = this._parseYBlock();\n\n    this.id = id;\n    this.flavour = flavour;\n    this.yChildren = yChildren;\n    this.version = version;\n\n    this.model = this._createModel(props);\n\n    this._observeYBlockChanges();\n  }\n\n  private _createModel(props: UnRecord) {\n    const _mutex = this._mutex;\n    const schema = this.schema.flavourSchemaMap.get(this.flavour);\n    if (!schema) {\n      throw new BlockSuiteError(\n        ErrorCode.ModelCRUDError,\n        `schema for flavour: ${this.flavour} not found`\n      );\n    }\n\n    const model = schema.model.toModel?.() ?? new BlockModel<object>();\n    model.schema = schema;\n    const signalWithProps = Object.entries(props).reduce(\n      (acc, [key, value]) => {\n        const data = signal(value);\n        const dispose = effect(() => {\n          const value = data.value;\n          if (!this.model) return;\n          _mutex(() => {\n            // @ts-expect-error allow magic props\n            this.model.props[key] = value;\n          });\n        });","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/framework/store/src/model/block/sync-controller.ts#L115-L151","documentation":"This is the tree-data-model counterpart of the FlatSyncController error: when SyncController builds a BlockModel for a regular block, it resolves schema.flavourSchemaMap.get(this.flavour) and throws ModelCRUDError if the flavour has no registered schema, because the model cannot be constructed without its schema.","triggerScenarios":"Hydrating or observing a standard (non-flat) block whose sys:flavour is absent from the Schema — e.g. a paragraph-like block from an unregistered or renamed flavour.","commonSituations":"Missing schema.register call in a custom editor build; docs shared between apps with different block sets; upgrades that renamed flavours without migrating stored docs.","solutions":["Register the missing block schema(s) before the doc hydrates","Diff the doc's flavour set against doc.schema.flavourSchemaMap.keys() to identify exactly what is missing","Register a legacy schema (old flavour string) alongside the new one for backward compatibility","Migrate sys:flavour values in old snapshots"],"exampleFix":"// before\nconst schema = new Schema();\nconst doc = workspace.createSession({ id: 'doc1', schema });\n// -> schema for flavour: my:block not found\n\n// after\nimport { MyBlock } from './my-block.js';\nschema.register([MyBlock]);\nconst doc = workspace.createSession({ id: 'doc1', schema });","handlingStrategy":"validation","validationCode":"const flavours = new Set<string>();\nfor (const [, yBlock] of doc.getBlockMap()) {\n  flavours.add(yBlock.get('sys:flavour') as string);\n}\nconst unregistered = [...flavours].filter(f => !schema.flavourSchemaMap.has(f));\nif (unregistered.length === 0) {\n  /* safe to hydrate */\n}","typeGuard":"const isFlavourRegistered = (schema: Schema, flavour: string): boolean =>\n  schema.flavourSchemaMap.has(flavour);","tryCatchPattern":"try {\n  const doc = workspace.createSession({ id, schema });\n} catch (e) {\n  if (e instanceof BlockSuiteError && e.code === ErrorCode.ModelCRUDError) {\n    // message names the flavour: register it or its legacy alias, retry\n  }\n  throw e;\n}","preventionTips":["Centralize schema registration so every build registers the same block set","Add a startup assertion that all flavours referenced by stored docs are registered","Never share docs between apps with different block registries without legacy schemas"],"tags":["blocksuite","schema","flavour","registration","block-model"],"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"}