# Disable Codex SQLite diagnostic logging on Windows

> Source: <https://gist.github.com/jun76/bf5f8fdde0e3866f537fc9422c65326d>
> Published: 2026-07-25 05:45:05+00:00

Last updated: July 25, 2026

Warning

This is an unofficial workaround, not an OpenAI-supported configuration. It disables local diagnostic records used for feedback and troubleshooting. Re-enable logging before collecting data for a support request.

This note explains how to stop the Windows Codex Desktop app from writing diagnostic records to `%USERPROFILE%\.codex\logs_2.sqlite`

.

It does not disable the separate databases that store conversation and application state.

[Issue #28224](https://github.com/openai/codex/issues/28224) in OpenAI's official GitHub repository reported that Codex SQLite diagnostic logging was generating excessive SSD writes.

The affected files were:

`%USERPROFILE%\.codex\logs_2.sqlite`

`%USERPROFILE%\.codex\logs_2.sqlite-wal`

`%USERPROFILE%\.codex\logs_2.sqlite-shm`

In the reported environment, high-frequency TRACE events were continuously inserted and deleted even when the retained row count remained stable.

These operations update the SQLite WAL, indexes, and checkpoints, so the amount written to the SSD can be much larger than the visible database size.

The reporter observed approximately 37 TB of total SSD writes over 21 days.

The following changes were subsequently merged to reduce the main sources of diagnostic-log traffic:

[Stop logging every Responses WebSocket event, PR #29432](https://github.com/openai/codex/pull/29432)[Filter noisy targets from persistent logs, PR #29457](https://github.com/openai/codex/pull/29457)[Stop persisting bridged log events, PR #29599](https://github.com/openai/codex/pull/29599)

The reporter observed an approximately 85% reduction in log traffic and closed Issue #28224 on June 23, 2026.

These changes did not disable diagnostic logging completely.

Continuing SQLite diagnostic writes have been reported in later versions, so environments where SSD write volume matters should measure the current behavior and apply an additional mitigation if necessary.

This procedure prevents new diagnostic records from being inserted into the `logs`

table in `logs_2.sqlite`

.

Normal conversations, source-code editing, and command execution do not depend on these diagnostic records.

Disabling them does reduce the information available for:

- Submitting a report through
`/feedback`

- Investigating crashes or connection failures
- Providing diagnostic evidence to OpenAI Support

This is a workaround based on a SQLite trigger, not an official Codex configuration option.

A Codex update or recreation of the log database may remove the trigger.

Confirm that the Python Launcher is available:

```
py -3 --version
```

Quit Codex Desktop, all Codex CLI sessions, and any VS Code instance running the Codex extension.

Open Task Manager and verify that no `Codex`

or `codex.exe`

processes remain.

Changing the database while another process holds it open may cause lock contention or WAL inconsistency.

Run the following command in PowerShell:

``` python
py -3 -c "import sqlite3,os; p=os.path.expanduser(r'~\.codex\logs_2.sqlite'); c=sqlite3.connect(p); c.execute('CREATE TRIGGER IF NOT EXISTS block_log_inserts BEFORE INSERT ON logs BEGIN SELECT RAISE(IGNORE); END;'); c.commit(); print('Diagnostic logging disabled:',p)"
```

This creates a trigger named `block_log_inserts`

that silently ignores every `INSERT`

into the `logs`

table.

Because the trigger discards inserts without returning an application error, it is less likely to cause a retry loop than making the database read-only.

Start Codex again and use it normally.

Diagnostic logging can be restored before troubleshooting a problem or contacting OpenAI Support.

Quit all Codex-related processes, then run:

``` python
py -3 -c "import sqlite3,os; p=os.path.expanduser(r'~\.codex\logs_2.sqlite'); c=sqlite3.connect(p); c.execute('DROP TRIGGER IF EXISTS block_log_inserts'); c.commit(); print('Diagnostic logging enabled:',p)"
```

Do not apply this workaround to the following files or directories:

`%USERPROFILE%\.codex\state_5.sqlite`

`%USERPROFILE%\.codex\goals_1.sqlite`

`%USERPROFILE%\.codex\sessions`

`%USERPROFILE%\.codex\history.jsonl`

Do not make the entire `.codex`

directory read-only.

These locations contain thread metadata, UI state, goals, session history, and other runtime state.

First, verify that the blocking trigger exists:

``` python
py -3 -c "import sqlite3,os; p=os.path.expanduser(r'~\.codex\logs_2.sqlite'); c=sqlite3.connect(p); print(c.execute(\"SELECT name FROM sqlite_master WHERE type='trigger' AND name='block_log_inserts'\").fetchall())"
```

The following output confirms that the trigger is registered:

```
[('block_log_inserts',)]
```

Next, start Codex and run this 60-second check:

``` python
py -3 -c "import sqlite3,os,time; p=os.path.expanduser(r'~\.codex\logs_2.sqlite'); q=lambda: sqlite3.connect(p).execute('SELECT COUNT(*), COALESCE(MAX(id),0) FROM logs').fetchone(); t=sqlite3.connect(p).execute(\"SELECT 1 FROM sqlite_master WHERE type='trigger' AND name='block_log_inserts'\").fetchone(); a=q(); print('trigger=',bool(t),'before=',a); time.sleep(60); b=q(); print('after=',b); print('PASS' if t and b[1]==a[1] else 'CHECK REQUIRED')"
```

Send a short prompt to Codex during the 60-second interval to exercise the normal logging path.

If the command reports both `trigger=True`

and `PASS`

, the trigger exists and no new log IDs were inserted during the observation period.

The existing row count may decrease because of cleanup, so the check uses the maximum row ID for its pass or fail decision.

If it reports `CHECK REQUIRED`

, quit Codex and run the disable command again.

The commands in this note assume that SQLite state is stored in the default `%USERPROFILE%\.codex`

directory.

If the location has been changed through `sqlite_home`

in `config.toml`

or the `CODEX_SQLITE_HOME`

environment variable, replace the value assigned to `p`

in each command with the actual path to `logs_2.sqlite`

.
