Intermittent 'Namespace not found' on local backend: add() uses two sequential mutations from action
- Dominant language
- TypeScript
- Stars
- 36
- Forks
- 13
- Avg merge
- 4h 2m
- Merged PRs (30d)
- 2
Description
## Bug Description
`rag.add()` intermittently throws "Namespace \ not found" on the `convex-local-backend` (OSS binary). The error occurs because `add()` calls two sequential component mutations from within an action:
1. `ctx.runMutation(this.component.namespaces.getOrCreate, ...)` -- creates namespace, returns `namespaceId`
2. `ctx.runMutation(this.component.entries.add, { entry: { namespaceId, ... } })` -- reads namespace via `ctx.db.get(namespaceId)` → intermittently returns `null`
The Convex best practices docs warn: *"Multiple runQuery/runMutations execute in separate transactions and aren't guaranteed to be consistent with each other."*
## Reproduction
The bug is **timing/load-sensitive** and manifests ~50% of the time when:
- Running on `convex-local-backend` (not observed on cloud)
- Calling `rag.add()` in a loop (e.g., 200+ entries) from a single action
- System is under load (e.g., parallel test backends, concurrent deployments)
**Simplified progressive isolation tests (20-200 iterations) do NOT reproduce the bug.** It only triggers under real-world conditions with system load.
### Minimal reproduction path
```typescript
// In an internalAction:
for (const entry of CATALOG_ENTRIES) { // ~200 entries
await rag.add(ctx, {
namespace: "global",
key: entry.slug,
text: entry.description,
});
}
```
The first `rag.add()` call creates the namespace via `getOrCreate`, then the subsequent `entries.add` mutation fails to see it.
## Error
```
Uncaught Error: Namespace jd79r35yh30qxy84rxpcnt7k1984b0pq not found
at assert (convex-helpers/index.js:113:0)
at handler (@convex-dev/rag/src/component/entries.ts:212:4)
```
Specifically, `entries.ts:210-211`:
```typescript
const namespace = await ctx.db.get(namespaceId);
assert(namespace, `Namespace ${namespaceId} not found`);
```
## Investigation Findings
1. `createFunctionHandle` is NOT involved -- the `add()` path (without `onComplete`) does not call it before `entries.add`
2. The error is `ctx.db.get(namespaceId)` returning `null` in the `entries.add` mutation for a namespace just created by `getOrCreate` in the previous mutation
3. Both mutations are in the same component, called sequentially from the same action
4. The issue does not occur on the Convex cloud backend
## Suggested Fix
Combine `getOrCreateNamespace` and `entries.add` into a single component mutation to avoid the cross-transaction visibility issue. This would align with Convex's best practice of batching `runMutation` calls.
## Versions
- `@convex-dev/rag`: 0.7.2
- `convex`: 1.34.1
- `convex-local-backend`: latest (downloaded from GitHub releases)
- `convex-helpers`: 0.1.114
Contributor guide
Assessment
This issue has not been assessed yet.