toeverything/AFFiNE · error · Error
Invalid key for: ${key}
Error message
Invalid key for: ${key} What it means
Thrown by getFirstKey in flat-native-y/utils when key.split('.').at(0) returns undefined, i.e. the key is empty or contains no usable first segment. getFirstKey is used to derive the top-level prop name from a dotted flat key; an empty/malformed key has no valid first segment so the function refuses rather than returning undefined and silently corrupting the proxy shape. Note this is a plain Error (no ErrorCode), so it is a lower-level invariant violation.
Source
Thrown at blocksuite/framework/store/src/reactive/flat-native-y/utils.ts:41
export function isEmptyObject(obj: UnRecord): boolean {
return Object.keys(obj).length === 0;
}
export function deleteEmptyObject(
obj: UnRecord,
key: string,
parent: UnRecord
): void {
if (isEmptyObject(obj)) {
delete parent[key];
}
}
export function getFirstKey(key: string): string {
const result = key.split('.').at(0);
if (!result) {
throw new Error(`Invalid key for: ${key}`);
}
return result;
}
export function bindOnChangeIfNeed(value: unknown, onChange: () => void): void {
if (value instanceof Text || Boxed.is(value)) {
value.bind(onChange);
}
}
View on GitHub (pinned to 26c515e050)
Solutions
- Sanitize prop keys before writing them to the Yjs map: drop or rename keys that are empty or start with '.'.
- Fix the producer/transformer to never emit empty path segments when building dotted flat keys.
- Add a guard at the loader boundary that filters out yMap entries whose keyWithoutPrefix is empty.
- When constructing dotted keys programmatically, filter out empty segments before joining.
Example fix
// before: building a flat key from possibly-empty segments
yBlock.set(`prop:${segment}`, value); // segment can be ''
// after: validate the segment
if (!segment) return;
yBlock.set(`prop:${segment}`, value); Defensive patterns
Strategy: validation
Validate before calling
export function assertValidDottedKey(key: string): void {
if (!key || !key.split('.').at(0)) {
throw new Error(`Invalid flat key: '${key}'`);
}
}
// before writing into a flat-data yBlock
const path = keyWithoutPrefix(rawKey);
assertValidDottedKey(path);
yBlock.set(`prop:${path}`, value); Type guard
export const isValidDottedKey = (key: string): boolean =>
key.length > 0 && Boolean(key.split('.').at(0)); Try / catch
// getFirstKey throws a plain Error (no ErrorCode)
try {
const first = getFirstKey(key);
} catch (e) {
if (e instanceof Error && /Invalid key for/.test(e.message)) {
// skip this malformed entry rather than abort initialization
return;
} else throw e;
} Prevention
- Filter empty segments when building dotted flat keys programmatically.
- Validate prop keys at the loader boundary.
- Never write 'prop:' (prefix-only) or 'prop:.' into flat-data yBlocks.
- Sanitize external data before importing into flat-data blocks.
When it happens
Trigger: Calling getFirstKey(''), getFirstKey('.'), or any key whose split on '.' yields only empty strings; produced by a flat-data transformer or external Yjs producer that emits prop keys like 'prop:' (prefix only) or 'prop:.'.
Common situations: Hand-built Yjs maps with malformed prop keys; a migration that strips a key down to its prefix; an encoder bug that joins an empty path; external data import with empty property names.
Related errors
- ReactiveProxyError
- Failed to read image size
- ErrorCode.DefaultRuntimeError
- ReactiveProxyError
- ReactiveProxyError
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/a83bcc589adff374.
Report an issue: GitHub.