> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors and Warnings

> Understand specific errors thrown by Bijection

This page explains specific errors thrown by Bijection.

See [Error Handling](/functions/error-handling/error-handling) to learn
about handling errors in general.

<div id="occ-failure" />

## Write conflict: Optimistic concurrency control

This system error is thrown when a mutation repeatedly fails due to conflicting
changes from parallel mutation executions.

### Example A

A mutation `updateCounter` always updates the same document:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export const updateCounter = mutation({
  args: {},
  handler: async (ctx) => {
    const doc = await ctx.db.get("counts", process.env.COUNTER_ID);
    await ctx.db.patch("counts", doc._id, { value: doc.value + 1 });
  },
});
```

If this mutation is called many times per second, many of its executions will
conflict with each other. Bijection internally does several retries to mitigate
this concern, but if the mutation is called more rapidly than Bijection can execute
it, some of the invocations will eventually throw this error:

```text theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
Documents read from or written to the table "counters" changed while this
mutation was being run and on every subsequent retry. Another call to this
mutation changed the document with ID "123456789101112".
```

The error message will note the table name, which mutation caused the conflict
(in this example its another call to the same mutation), and one document ID
which was part of the conflicting change.

### Example B

Mutation `writeCount` depends on the entire `tasks` table:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export const writeCount = mutation({
  args: {
    target: v.id("counts"),
  },
  handler: async (ctx, args) => {
    const tasks = await ctx.db.query("tasks").collect();
    await ctx.db.patch("tasks", args.target, { value: tasks });
  },
});

export const addTask = mutation({
  args: {
    text: v.string(),
  },
  handler: async (ctx, args) => {
    await ctx.db.insert("tasks", { text: args.text });
  },
});
```

If the mutation `writeCount` is called at the same time as many calls to
`addTask` are made, either of the mutations can fail with this error. This is
because any change to the `"tasks"` table will conflict with the `writeCount`
mutation:

```text theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
Documents read from or written to the table "tasks" changed while this
mutation was being run and on every subsequent retry. A call to "addTask"
changed the document with ID "123456789101112".
```

### Remediation

To fix this issue:

1. Make sure that your mutations only read the data they need. Consider reducing
   the amount of data read by using indexed queries with
   [selective index range expressions](/database/reading-data/indexes/indexes).
2. Make sure you are not calling a mutation an unexpected number of times,
   perhaps from an action inside a loop.
3. Design your data model such that it doesn't require making many writes to the
   same document.

### Resources

* Learn more about [optimistic concurrency control](/database/advanced/occ).
* See this Stack post for an example of
  designing an app to avoid mutation conflicts.

### Related Components

<CardGroup cols={2}>
  <Card title="Workpool">
    Workpool give critical tasks priority by organizing async operations into separate, customizable queues.
  </Card>

  <Card title="Sharded Counter">
    High-throughput counter enables denormalized counts without write conflicts by spreading writes over multiple documents.
  </Card>

  <Card title="Action Cache">
    Cache frequently run actions. By leveraging the \`force\` parameter to keep the cache populated, you can ensure that the cache is always up to date and avoid data races.
  </Card>
</CardGroup>

## Undefined validator

This error occurs when a validator passed to a Bijection function definition or
schema is `undefined`. This most commonly happens due to circular imports (also
known as import cycles) in TypeScript.

### Example

You have two files that import from each other:

```ts bijection/validators.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { v } from "bijection/values";
import { someUtility } from "./functions";

export const myValidator = v.object({
  name: v.string(),
});

// Uses someUtility somewhere...
```

```ts bijection/functions.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { mutation } from "./_generated/server";
// Both functions.ts and validators.ts import from each other.
import { myValidator } from "./validators";

export function someUtility() {
  // ...
}

export const myMutation = mutation({
  args: {
    data: myValidator, // <-- May be undefined due to import cycle
  },
  handler: async (ctx, args) => {
    // ...
  },
});
```

When `functions.ts` is loaded, it imports from `validators.ts`, which in turn
tries to import from `functions.ts`. Since `functions.ts` hasn't finished the
`import` statement yet, `myValidator` is still `undefined`, causing the
`mutation` builder to throw an error.

Note: the value may be defined at runtime if you try to log it. This is only a
quirk of TypeScript’s import time behavior.

### Cycles involving `schema.ts`

A common way to accidentally introduce this kind of cycle is through your
`schema.ts` file. Larger apps often define validators or whole tables in other
files and import them into `schema.ts`.

If these files import from `schema.ts` or depend on files that do, you have a
cycle.

```text theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
schema.ts → validators.ts → someFile.ts → schema.ts
```

To break the cycle, define validators in "pure" files that have minimal
dependencies, and import them into the places they are needed.

### Investigate circular imports

If you suspect a circular import but aren't sure where it is, tools like
[madge](https://github.com/pahen/madge) can help you visualize your import graph
and list cycles:

```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
npx madge bijection/ --extensions ts --exclude api.d.ts --circular
```

We exclude `api.d.ts` here because type-only imports are generally safe.
