toeverything/AFFiNE · error · Error
props is only supported in flat data model
Error message
props is only supported in flat data model
What it means
BlockModel.props returns the reactive proxy stored in _props, but only FlatSyncController ever assigns _props — it is used when a block's schema declares isFlatData: true (block.ts:54). In the default tree data model, SyncController copies props directly onto the model instance and leaves _props undefined, so this getter throws to signal that the proxy API does not exist for this block.
Source
Thrown at blocksuite/framework/store/src/model/block/block-model.ts:83
stash!: (prop: keyof Props & string) => void;
get text(): Text | undefined {
return (this.props as { text?: Text }).text;
}
set text(text: Text) {
if (this.keys.includes('text')) {
(this.props as { text?: Text }).text = text;
}
}
yBlock!: YBlock;
_props!: SignaledProps<Props>;
get props() {
if (!this._props) {
throw new Error('props is only supported in flat data model');
}
return this._props;
}
get flavour(): string {
return this.schema.model.flavour;
}
get version() {
return this.schema.version;
}
get children() {
return this._childModels.value;
}
get store() {
return this._store;View on GitHub (pinned to b4c8548c09)
Solutions
- Access props as plain fields on the model instead (model.title, model.text) — tree-model blocks expose props directly on the instance
- If you own the block schema and need proxy-based access, define it with isFlatData: true and re-create existing blocks
- In shared code, branch on whether the flat proxy exists (check the private _props or model.keys) before touching model.props
Example fix
// before
const title = model.props.title; // throws: props is only supported in flat data model
// after — tree data model exposes props directly on the model
const title = model.title;
// or, if you own the schema and want the flat proxy:
const MyBlock = defineBlockSchema({
flavour: 'my:block',
isFlatData: true,
props: () => ({ title: '' as string }),
}); Defensive patterns
Strategy: type-guard
Type guard
function hasFlatProps(model: BlockModel): boolean {
return (model as unknown as { _props?: unknown })._props !== undefined;
} Prevention
- Never read model.props on blocks you did not define with isFlatData: true
- Prefer typed field access (model.text, model.title) which works in both data models
- Guard shared utilities with hasFlatProps(model) before touching the proxy
When it happens
Trigger: Reading model.props (or assigning model.text = new Text(...), whose setter writes through this.props) on any block whose schema does not set isFlatData: true — e.g. doc.getBlockById(id).props.title on a standard affine:paragraph block.
Common situations: Copying a snippet written for flat-data-model blocks into code that runs against tree-model blocks; upgrading BlockSuite versions where a block family changed data model; generic utility code that assumes every model exposes a props proxy.
Related errors
- ReactiveProxyError
- ErrorCode.MissingViewModelError
- ErrorCode.ModelCRUDError
- ErrorCode.ModelCRUDError
- Invalid key for: ${key}
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/930f74b8a94fd28b.
Report an issue: GitHub.