@@ -258,9 +258,11 @@ todoCollection.insert(newTodo)
258258// Error: Collection.insert called directly (not within an explicit transaction) but no 'onInsert' handler is configured
259259```
260260
261- ### Duplicate Key Errors
261+ ### Insert Operation Errors
262262
263- Inserting items with existing keys will throw:
263+ #### DuplicateKeyError
264+
265+ Thrown when inserting items with existing keys:
264266
265267``` ts
266268import { DuplicateKeyError } from " @tanstack/db"
@@ -270,28 +272,90 @@ try {
270272} catch (error ) {
271273 if (error instanceof DuplicateKeyError ) {
272274 console .log (` Duplicate key: ${error .message } ` )
275+ // Consider using update() instead, or check if item exists first
273276 }
274277}
275278```
276279
277- ### Schema Validation Errors
280+ #### UndefinedKeyError
278281
279- Schema validation must be synchronous :
282+ Thrown when an object is created without a defined key :
280283
281284``` ts
282- const todoCollection = createCollection ({
285+ import { UndefinedKeyError } from " @tanstack/db"
286+
287+ const collection = createCollection ({
283288 id: " todos" ,
284- getKey : (todo ) => todo .id ,
285- schema: {
286- " ~standard" : {
287- validate : async (data ) => { // Async validation not allowed
288- // ...
289- }
290- }
291- }
289+ getKey : (item ) => item .id ,
292290})
293291
294- // Will throw: Schema validation must be synchronous
292+ try {
293+ collection .insert ({ text: " Todo" }) // Missing 'id' field
294+ } catch (error ) {
295+ if (error instanceof UndefinedKeyError ) {
296+ console .log (" Item is missing required key field" )
297+ // Ensure your items have the key field defined by getKey
298+ }
299+ }
300+ ```
301+
302+ ### Update Operation Errors
303+
304+ #### UpdateKeyNotFoundError
305+
306+ Thrown when trying to update a key that doesn't exist in the collection:
307+
308+ ``` ts
309+ import { UpdateKeyNotFoundError } from " @tanstack/db"
310+
311+ try {
312+ todoCollection .update (" nonexistent-key" , draft => {
313+ draft .completed = true
314+ })
315+ } catch (error ) {
316+ if (error instanceof UpdateKeyNotFoundError ) {
317+ console .log (" Key not found - item may have been deleted" )
318+ // Consider using insert() if the item doesn't exist
319+ }
320+ }
321+ ```
322+
323+ #### KeyUpdateNotAllowedError
324+
325+ Thrown when attempting to change an item's key (not allowed - delete and re-insert instead):
326+
327+ ``` ts
328+ import { KeyUpdateNotAllowedError } from " @tanstack/db"
329+
330+ try {
331+ todoCollection .update (" todo-1" , draft => {
332+ draft .id = " todo-2" // Not allowed!
333+ })
334+ } catch (error ) {
335+ if (error instanceof KeyUpdateNotAllowedError ) {
336+ console .log (" Cannot change item keys" )
337+ // Instead, delete the old item and insert a new one
338+ }
339+ }
340+ ```
341+
342+ ### Delete Operation Errors
343+
344+ #### DeleteKeyNotFoundError
345+
346+ Thrown when trying to delete a key that doesn't exist:
347+
348+ ``` ts
349+ import { DeleteKeyNotFoundError } from " @tanstack/db"
350+
351+ try {
352+ todoCollection .delete (" nonexistent-key" )
353+ } catch (error ) {
354+ if (error instanceof DeleteKeyNotFoundError ) {
355+ console .log (" Key not found - item may have already been deleted" )
356+ // This may be acceptable in some scenarios (idempotent deletes)
357+ }
358+ }
295359```
296360
297361## Sync Error Handling
@@ -432,22 +496,139 @@ tx2.mutate(() => collection.update("1", draft => { draft.value = "B" })) // Same
432496tx1 .rollback () // tx2 is automatically rolled back
433497```
434498
435- ### Handling Invalid State Errors
499+ ### Transaction Lifecycle Errors
500+
501+ Transactions validate their state before operations to prevent misuse. Here are the specific errors you may encounter:
502+
503+ #### MissingMutationFunctionError
504+
505+ Thrown when creating a transaction without a required ` mutationFn ` :
506+
507+ ``` ts
508+ import { MissingMutationFunctionError } from " @tanstack/db"
509+
510+ try {
511+ const tx = createTransaction ({}) // Missing mutationFn
512+ } catch (error ) {
513+ if (error instanceof MissingMutationFunctionError ) {
514+ console .log (" mutationFn is required when creating a transaction" )
515+ }
516+ }
517+ ```
518+
519+ #### TransactionNotPendingMutateError
520+
521+ Thrown when calling ` mutate() ` after a transaction is no longer pending:
522+
523+ ``` ts
524+ import { TransactionNotPendingMutateError } from " @tanstack/db"
525+
526+ const tx = createTransaction ({ mutationFn : async () => {} })
527+
528+ await tx .commit ()
529+
530+ try {
531+ tx .mutate (() => {
532+ collection .insert ({ id: " 1" , text: " Item" })
533+ })
534+ } catch (error ) {
535+ if (error instanceof TransactionNotPendingMutateError ) {
536+ console .log (" Cannot mutate - transaction is no longer pending" )
537+ }
538+ }
539+ ```
540+
541+ #### TransactionNotPendingCommitError
542+
543+ Thrown when calling ` commit() ` after a transaction is no longer pending:
544+
545+ ``` ts
546+ import { TransactionNotPendingCommitError } from " @tanstack/db"
547+
548+ const tx = createTransaction ({ mutationFn : async () => {} })
549+ tx .mutate (() => collection .insert ({ id: " 1" , text: " Item" }))
550+
551+ await tx .commit ()
552+
553+ try {
554+ await tx .commit () // Trying to commit again
555+ } catch (error ) {
556+ if (error instanceof TransactionNotPendingCommitError ) {
557+ console .log (" Transaction already committed" )
558+ }
559+ }
560+ ```
561+
562+ #### TransactionAlreadyCompletedRollbackError
436563
437- Transactions validate their state before operations :
564+ Thrown when calling ` rollback() ` on a transaction that's already completed :
438565
439566``` ts
567+ import { TransactionAlreadyCompletedRollbackError } from " @tanstack/db"
568+
440569const tx = createTransaction ({ mutationFn : async () => {} })
570+ tx .mutate (() => collection .insert ({ id: " 1" , text: " Item" }))
441571
442- // Complete the transaction
443572await tx .commit ()
444573
445- // These will throw:
446- tx .mutate (() => {}) // Error: You can no longer call .mutate() as the transaction is no longer pending
447- tx .commit () // Error: You can no longer call .commit() as the transaction is no longer pending
448- tx .rollback () // Error: You can no longer call .rollback() as the transaction is already completed
574+ try {
575+ tx .rollback () // Can't rollback after commit
576+ } catch (error ) {
577+ if (error instanceof TransactionAlreadyCompletedRollbackError ) {
578+ console .log (" Cannot rollback - transaction already completed" )
579+ }
580+ }
449581```
450582
583+ ### Sync Transaction Errors
584+
585+ When working with sync transactions, these errors can occur:
586+
587+ #### NoPendingSyncTransactionWriteError
588+
589+ Thrown when calling ` write() ` without an active sync transaction:
590+
591+ ``` ts
592+ const collection = createCollection ({
593+ id: " todos" ,
594+ sync: {
595+ sync : ({ write }) => {
596+ // Calling write without begin() first
597+ write ({ type: " insert" , value: { id: " 1" , text: " Todo" } })
598+ // Error: No pending sync transaction to write to
599+ }
600+ }
601+ })
602+ ```
603+
604+ #### SyncTransactionAlreadyCommittedWriteError
605+
606+ Thrown when calling ` write() ` after the sync transaction is already committed:
607+
608+ ``` ts
609+ const collection = createCollection ({
610+ id: " todos" ,
611+ sync: {
612+ sync : ({ begin , write , commit }) => {
613+ begin ()
614+ commit ()
615+
616+ // Trying to write after commit
617+ write ({ type: " insert" , value: { id: " 1" , text: " Todo" } })
618+ // Error: The pending sync transaction is already committed
619+ }
620+ }
621+ })
622+ ```
623+
624+ #### NoPendingSyncTransactionCommitError
625+
626+ Thrown when calling ` commit() ` without an active sync transaction.
627+
628+ #### SyncTransactionAlreadyCommittedError
629+
630+ Thrown when calling ` commit() ` on a sync transaction that's already committed.
631+
451632## Best Practices
452633
4536341 . ** Use instanceof checks** - Use ` instanceof ` instead of string matching for error handling:
@@ -471,10 +652,13 @@ tx.rollback() // Error: You can no longer call .rollback() as the transaction is
471652## Example: Complete Error Handling
472653
473654``` tsx
474- import {
475- createCollection ,
655+ import {
656+ createCollection ,
476657 SchemaValidationError ,
477658 DuplicateKeyError ,
659+ UpdateKeyNotFoundError ,
660+ DeleteKeyNotFoundError ,
661+ TransactionNotPendingCommitError ,
478662 createTransaction
479663} from " @tanstack/db"
480664import { useLiveQuery } from " @tanstack/react-db"
0 commit comments