toeverything/AFFiNE · error · BlockSuiteError
ValueNotExists
ValueNotExists
Error message
Key is not defined in the EdgelessClipboardConfig
What it means
The in-memory table adapter enforces primary-key uniqueness at insert time: it stringifies data[keyField] and rejects the insert when that key already exists in the table's map, mirroring a database UNIQUE constraint. This makes duplicate-key bugs surface deterministically in tests and memory-backed runs instead of silently overwriting the earlier row.
Solutions
- If the row may already exist, check first with find({ where: { [keyField]: key } }) and update() instead of insert()
- Generate genuinely unique keys (crypto.randomUUID or a monotonic counter) instead of fixed or low-entropy ids
- Reset/recreate the memory DB between test cases so seeded keys do not carry over
Example fix
// before
table.insert({ data: { id: 'a1', name: 'x' } });
table.insert({ data: { id: 'a1', name: 'x' } }); // Record with key a1 already exists
// after
const existing = table.find({ where: { byKey: 'a1' } });
if (existing.length > 0) {
table.update({ where: { byKey: 'a1' }, data: { name: 'x' } });
} else {
table.insert({ data: { id: crypto.randomUUID(), name: 'x' } });
} Defensive patterns
Strategy: validation
Validate before calling
function upsert(table: TableAdapter, keyField: string, data: Record<string, any>) {
const key = String(data[keyField]);
const exists = table.find({ where: { byKey: key } }).length > 0;
if (exists) {
return table.update({ where: { byKey: key }, data });
}
return table.insert({ data });
} Type guard
null
Prevention
- Check existence with find({ where: { byKey } }) before insert, or use a find-then-update upsert helper
- Generate keys with crypto.randomUUID() instead of fixed or low-entropy values
- Reset memory-backed tables between tests so seeded keys cannot accumulate
- Make write paths idempotent on the client (disable double submit)
When it happens
Trigger: Inserting the same entity key twice (retry after an error, double submit, duplicate import); fixture/setup code running per test against a shared memory DB without clearing; keys generated non-uniquely (Math.random collisions, fixed ids); using insert where an update/upsert was intended.
Common situations: Test seeds accumulating across runs; client double-clicks and idempotency gaps; auto-generated ids not unique across workers or sessions.
Related errors
- Param not a number
- ValueNotExists
- A curve must have at least three points.
- Bad segment
- Path data ended short
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/fc3875752d50d783.
Report an issue: GitHub.
Appendix: source
Thrown at blocksuite/affine/blocks/surface/src/extensions/clipboard-config.ts:65
index?: number
) => {
const block = await this.std.clipboard.pasteBlockSnapshot(
snapshot,
doc,
parent,
index
);
return block?.id ?? null;
};
abstract createBlock(
snapshot: BlockSnapshot,
context: ClipboardConfigCreationContext
): string | null | Promise<string | null>;
static override setup(di: Container) {
if (!this.key) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
'Key is not defined in the EdgelessClipboardConfig'
);
}
di.add(
this as unknown as { new (std: BlockStdScope): EdgelessClipboardConfig },
[StdIdentifier]
);
di.addImpl(EdgelessClipboardConfigIdentifier(this.key), provider =>
provider.get(this)
);
}
}
View on GitHub (pinned to b4c8548c09)