toeverything/AFFiNE · error · BlockSuiteError

ErrorCode.ModelCRUDError

ErrorCode.ModelCRUDError

Error message

schema for flavour: ${this.flavour} not found

What it means

Thrown by `FlatSyncController._createModel` when `schema.flavourSchemaMap.get(this.flavour)` returns undefined. The controller is constructing a `BlockModel` from a yjs block map; the block's flavour has no matching schema, meaning the flavour was never registered with the `Schema` passed to the store. Note `_parseYBlock` already throws the same message earlier if the schema is missing there too.

Source

Thrown at blocksuite/framework/store/src/model/block/flat-sync-controller.ts:43

    readonly schema: Schema,
    readonly yBlock: YBlock,
    readonly doc?: Store,
    readonly onChange?: (key: string, isLocal: boolean) => void
  ) {
    const { id, flavour, version, yChildren, props } = this._parseYBlock();

    this.id = id;
    this.flavour = flavour;
    this.yChildren = yChildren;
    this.version = version;

    this.model = this._createModel(props);
  }

  private _createModel(props: Set<string>) {
    const schema = this.schema.flavourSchemaMap.get(this.flavour);
    if (!schema) {
      throw new BlockSuiteError(
        ErrorCode.ModelCRUDError,
        `schema for flavour: ${this.flavour} not found`
      );
    }

    const model = schema.model.toModel?.() ?? new BlockModel<object>();
    const defaultProps = schema.model.props?.(internalPrimitives);
    model.schema = schema;

    model.id = this.id;
    model.keys = Array.from(props);
    model.yBlock = this.yBlock;
    const reactive = new ReactiveFlatYMap(
      this.yBlock,
      model.deleted,
      this.onChange,
      defaultProps
    );

View on GitHub (pinned to 26c515e050)

Solutions

  1. Register every flavour the doc may contain with the `Schema` before constructing the store / loading the doc.
  2. Gate doc load on flavour registration being complete (await the module that registers the schema).
  3. If you intentionally receive foreign flavours, filter them out of the yjs map before model creation, or register a stub schema.

Example fix

// before: store built with a partial schema
const schema = new Schema([PageBlockSchema]);
const store = createStore({ schema, id: 'doc' });
store.load(binaryContainingCustomBlock); // throws: schema for flavour not found

// after: register every flavour the doc may contain
const schema = new Schema([PageBlockSchema, CustomBlockSchema]);
const store = createStore({ schema, id: 'doc' });
store.load(binaryContainingCustomBlock);
Defensive patterns

Strategy: validation

Validate before calling

// verify every flavour referenced by the doc is in the schema before loading
function allFlavoursRegistered(schema: Schema, flavours: string[]): boolean {
  return flavours.every(f => schema.flavourSchemaMap.has(f));
}

const flavours = collectFlavoursFromYDoc(yDoc);
if (!allFlavoursRegistered(schema, flavours)) {
  throw new Error('Register all block flavours before loading the doc');
}

Type guard

function schemaHasFlavour(schema: Schema, flavour: string): boolean {
  return schema.flavourSchemaMap.has(flavour);
}

Try / catch

try {
  store.load(binary);
} catch (e) {
  if (e instanceof BlockSuiteError && e.code === ErrorCode.ModelCRUDError) {
    console.error('Schema missing flavour:', e.message);
  }
}

Prevention

When it happens

Trigger: A yjs document contains a block whose `sys:flavour` is not in the schema — e.g. collaborative peer with a block flavour the local app does not register, a snapshot import of an unknown flavour, or the `Schema` was built without all the block `defineBlockSchema` calls.

Common situations: App build A registers `{affine:page}` and build B adds `{affine:custom}`; B's doc syncs to A and A throws. Forgetting to call `Schema` with all block flavours; lazy-loading a block flavour but the doc loads before the flavour registration completes.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/2f2cddc48e0d08eb. Report an issue: GitHub.