toeverything/AFFiNE · error · BlockSuiteError
ErrorCode.ModelCRUDError
ErrorCode.ModelCRUDError
Error message
schema for flavour: ${flavour} not found What it means
Thrown by DocCRUD.addBlock: the flavour passed in is not present in schema.flavourSchemaMap. This is the public write-path equivalent of the parse-path schema errors; addBlock needs the schema to compute the version, default props, and validate parent/child rules, so an unknown flavour is rejected before any Yjs mutation.
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 26c515e050)
Solutions
- Register the flavour's schema before calling addBlock.
- Pull flavour constants from the block package's exports instead of hard-coding strings.
- Add a schema.has(flavour) precondition check (or unit test) at call sites that accept dynamic flavours.
- If the flavour was renamed, migrate callers or add an alias in the schema.
Example fix
// before
store.addBlock('affine:list', { type: 'bulleted' }, parent);
// after: import the flavour constant
import { ListBlockSchema } from '@blocksuite/affine/blocks/list';
schema.register([ListBlockSchema]);
store.addBlock(ListBlockSchema.model.flavour, { type: 'bulleted' }, parent); Defensive patterns
Strategy: type-guard
Validate before calling
export function assertCanAddBlock(store: Store, flavour: string): void {
if (!store.schema.flavourSchemaMap.has(flavour)) {
throw new Error(`Cannot addBlock: flavour '${flavour}' not registered`);
}
}
assertCanAddBlock(store, 'affine:paragraph');
store.addBlock('affine:paragraph', {}, parent); Type guard
export const isAddableFlavour = (store: Store, flavour: string): boolean => store.schema.flavourSchemaMap.has(flavour);
Try / catch
try {
store.addBlock(flavour, props, parent);
} catch (e) {
if (e instanceof BlockSuiteError && e.code === ErrorCode.ModelCRUDError && /schema for flavour/.test(e.message)) {
disableUiForFlavour(flavour); // or register then retry
} else throw e;
} Prevention
- Source flavour strings from schema constants rather than literals.
- Register every flavour at app startup, before any user action.
- Unit-test addBlock call paths against the registered schema.
- Guard dynamic-flavour call sites with schema.flavourSchemaMap.has.
When it happens
Trigger: Calling store.addBlock('affine:foo', ...) where 'affine:foo' was never registered; passing a typo'd or stale flavour string; using a flavour from a different BlockSuite major version.
Common situations: Hard-coded flavour strings that drift from the registered schema; feature-flagged block not registered in the current build; copy-paste of a flavour literal that has since been renamed; SSR build omitting client-only block modules.
Related errors
- ErrorCode.ModelCRUDError
- ErrorCode.ModelCRUDError
- ErrorCode.ModelCRUDError
- ModelCRUDError
- ReactiveProxyError
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/6c8b7312c3c8e08d.
Report an issue: GitHub.