# Database fixes for JsonDb and MongoDB

> Agno's JsonDb publishes each table write through a staging file, so a write that fails halfway leaves the saved table readable. MongoDb, AsyncMongoDb and MongoVectorDb match session name, memory and keyword filters as literal text.

- Published: 2026-10-08
- Author: Rudy Mizrahi Celekli
- Categories: Changelog
- Canonical: https://www.agno.com/blog/database-fixes-for-jsondb-and-mongodb
- Markdown: https://www.agno.com/blog/database-fixes-for-jsondb-and-mongodb.md

Agno's `JsonDb` now serializes each table to a hidden `.agno-json-<id>.tmp` file in the same folder and publishes it with `os.replace`. Earlier releases opened the table itself in write mode first, so an error during `json.dump` left a cut-off file and every later read failed.

### `JsonDb` keeps the last saved table when a write fails

We saved one session, then made the next write fail after its first byte with `No space left on device`. Real output on the previous release and on this one:

```text
Before: write failed: [Errno 28] No space left on device
        file on disk: '['
        read failed: JSONDecodeError Expecting value: line 1 column 2 (char 1)

Now:    write failed: [Errno 28] No space left on device
        file on disk: '[\n  {\n    "session_id": "saved",\n    "ag'
        sessions: ['saved']
```

The failing write still raises, so your code hears about it. The staging file takes the existing table's owner and mode bits. When a path can't be replaced atomically, such as a bind-mounted table, a read-only folder or a table owned by another user, `JsonDb` falls back to writing the file in place. A table created for the first time uses an exclusive create, so it never truncates a table that a concurrent writer just published.

### MongoDB filters match the text you typed

`MongoDb.get_sessions(session_name=...)`, `MongoDb.get_user_memories(search_content=...)`, the same two methods on `AsyncMongoDb`, and `MongoVectorDb.keyword_search` sent the caller's string to MongoDB as a `$regex`. A value with an unbalanced `(` is an invalid pattern, so AgentOS answered `GET /sessions` and `GET /memories` with HTTP 500. A `.` matched any character, so `v1.2` also found `v1x2`. Agno now runs each value through `re.escape` and keeps the case-insensitive flag.

Real output from `MongoDb.get_sessions` on an in-memory mongomock database holding `Release v1.2 (draft)` and `Release v1x2 final`:

```text
Before: session_name='v1.2'   -> ['Release v1.2 (draft)', 'Release v1x2 final']
        session_name='(draft' -> error missing ), unterminated subpattern at position 0

Now:    session_name='v1.2'   -> ['Release v1.2 (draft)']
        session_name='(draft' -> ['Release v1.2 (draft)']
```

See the [JsonDb cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/06_storage/json_db/json_for_agent.py) and the [MongoDB cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/06_storage/mongo/mongodb_for_agent.py), and learn more about [JsonDb](https://docs.agno.com/database/providers/json/overview), [MongoDB storage](https://docs.agno.com/database/providers/mongo/overview) and the [MongoDB vector store](https://docs.agno.com/knowledge/vector-stores/mongodb/overview) in the documentation.
