Runtime Merge Errors
Relevant source files
The following files were used as context for generating this wiki page:
Keyfold is designed to be failure-safe, ensuring that the merging process never leaves a state tree in a partially mutated or corrupted state. Runtime merge errors occur when the library encounters data in either the base state or the incoming delta that violates the strict contract required for immutable folding and keyed-list reconciliation.
When a violation is detected during the execution of a merger function, a KeyfoldMergeError is thrown. This differs from KeyfoldConfigError, which is reserved for malformed policies detected during the creation of the merger itself via createMerger.
Sources: src/errors.ts:1-10, AGENTS.md, README.md
Error Categories
Runtime errors primarily arise from identity conflicts, type mismatches in keyed structures, and the presence of reserved fields where they are prohibited.
Keyed List Identity Violations
Keyfold relies on unique and stable identities to perform O(list) reconciliation. Most runtime errors occur during the indexDelta or reconcile phases when these identities are missing, duplicated, or invalid.
| Error Condition | Description | File Reference |
|---|---|---|
| Duplicate Delta Identity | Multiple items in the same delta list share the same identity. | src/reconcile.ts |
| Duplicate Base Identity | The base list already contains duplicate identities (corrupt state). | src/reconcile.ts |
| Invalid Identity Type | An identity field contains something other than a string or non-NaN number. | src/reconcile.ts |
| Missing Identity | An item in a keyed list is missing the configured identity field. | src/reconcile.ts |
| Reserved Wire Token | An identity field uses DELETE_TOKEN while wireDeletes is enabled. | src/reconcile.ts |
Sources: src/reconcile.ts:25-145, test/reconcile.test.ts:135-155
Structural and Type Violations
Keyfold expects keyed list items to be plain objects to facilitate merging. If the runtime data does not match the expected structure, the merger aborts the operation.
- Non-Object Items: Thrown if an item in a list (base or delta) is not a plain object when a
keyBypolicy is active for that path. - Reserved Fields in Base: Thrown if a base item contains the
$deletefield, which is reserved strictly for delta tombstones. - Malformed Tombstones: A tombstone must be an object containing only the identity field and
$delete: true. Any additional fields in a tombstone will trigger an error.
Sources: src/reconcile.ts:40-45, src/reconcile.ts:128-140, test/reconcile.test.ts:184-188
Error Handling Flow
The following diagram illustrates how the reconcile function validates data and triggers errors during the merging process.
The reconciliation process validates the entire delta index before processing the base list, adhering to the library's failure-safe guarantee.
Sources: src/reconcile.ts:25-75
Failure-Safety Mechanism
Keyfold implements a "Failure-Safe" architecture. Because the merger builds the new state tree incrementally without mutating the original base, a thrown KeyfoldMergeError effectively rolls back the entire operation. No partial writes are ever committed to the application state.
// Example of failure-safe behavior in tests
test("throws for duplicate delta identity without mutating base", () => {
const base = state();
const snapshot = structuredClone(base);
const items = [{ id: "a" }, { id: "a" }]; // Duplicate
expect(() => merge(base, { items })).toThrow(KeyfoldMergeError);
expect(base).toEqual(snapshot); // Base remains untouched
});
Sources: test/reconcile.test.ts:135-155, AGENTS.md
Summary of Runtime Validation Logic
The readKeyedItem and isTombstone functions serve as the primary gatekeepers for runtime data integrity.
function readKeyedItem(
value: unknown,
identityField: string,
wireDeletes: boolean,
path: string,
source: "base" | "delta",
): { id: string | number; item: Record<string, unknown> } {
if (!isPlainObject(value)) {
throw new KeyfoldMergeError(
`${source} item at '${path}' is not an object with identity field '${identityField}'`,
);
}
// ... validation of identity field presence and type
}
Sources: src/reconcile.ts:101-112
Runtime merge errors in Keyfold act as a critical defensive layer, preventing silent state corruption when internal invariants—such as the uniqueness of keyed identities—are violated by external data sources.