How I reduced Codex SSD writes by stopping diagnostic logs

An illustration of diagnostic logs streaming from a laptop to an SSD drive

People have been discussing a problem where Codex writes an unusually large amount of data to an SSD on Mac. The suspected cause is a high volume of TRACE-level diagnostic logs written to ~/.codex/logs_2.sqlite.

I checked my own environment and found that about 965 log rows were added in 30 seconds. I then added a SQLite trigger that ignores new inserts into the diagnostic-log table. In a follow-up measurement, I confirmed that no new log rows were being added.

This article explains what is happening, the numbers I observed on my Mac, the unofficial emergency workaround I tried, and how to undo it. The information is current as of July 29, 2026.

Here is the post that prompted this investigation

The starting point was a post about Codex’s SSD write problem and a way to disable diagnostic logging.

Codex may keep writing diagnostic logs to the SSD

Codex stores diagnostic logs used for feedback and troubleshooting in these SQLite files:

~/.codex/logs_2.sqlite
~/.codex/logs_2.sqlite-wal
~/.codex/logs_2.sqlite-shm

The problem is that TRACE-level logs can be appended at a high frequency during normal use. Writes happen not only to the database but also to the WAL (Write-Ahead Log), which can increase both SSD write volume and file size.

OpenAI Codex issue #31542 describes HTTP request bodies and streaming response payloads being written to TRACE logs as a possible cause. Issue #34291 reports cases where large JSON-RPC data, such as an MCP tool list, creates rows of around 1.3 MB. Both issues were still open as of July 29, 2026.

Changing RUST_LOG, which filters logs sent to the terminal, may not stop SQLite logging. The terminal layer and the SQLite diagnostic-log sink use separate filters.

What I found on my Mac

I inspected the diagnostic database in an environment running Codex CLI 0.144.4, using read-only queries.

  • logs_2.sqlite was about 371 MB
  • It contained 119,671 retained rows, with an estimated data size of about 117.3 MiB
  • TRACE-level logs accounted for about 34% of the estimated data size
  • Four large TRACE records in codex_http_client::transport were about 2.18–2.19 MiB each
  • During 30 seconds of normal activity, 965 rows totaling an estimated 885 KB were added (about 32 rows per second)

The main source appeared to be TRACE logging from codex_api::sse::responses. The rate was close to the 25–41 rows per second reported in the official issues, so I concluded that the writes were ongoing rather than just old logs left behind.

TRIM was enabled on the Mac’s SSD, but the standard tools did not show its total written data or remaining life. I did not measure how much SSD life this workaround would save; I only checked whether the large stream of new log rows stopped.

What I tried: an SQLite trigger that ignores log inserts

I tried an SQLite trigger that ignores log inserts without raising an error. This is not an official Codex setting. It is an unofficial emergency workaround that directly modifies the database.

CREATE TRIGGER IF NOT EXISTS block_log_inserts
 BEFORE INSERT ON logs
 BEGIN
   SELECT RAISE(IGNORE);
 END;

Because inserts are ignored, new diagnostic rows are not saved. This does not mean that every SQLite-related write disappears, but it is intended to stop the large stream of TRACE rows and the resulting database growth.

Quit every Codex-related process first

Before changing the SQLite files, quit the Codex app, Codex CLI, the Codex extension for VS Code, and anything else that might have the database open.

You can search for process names with pgrep -fl 'Codex|codex', but on macOS this may also find ChatGPT’s internal browser_crashpad_handler. Checking whether a process actually has the database open with lsof is safer.

lsof \
  ~/.codex/logs_2.sqlite \
  ~/.codex/logs_2.sqlite-wal \
  ~/.codex/logs_2.sqlite-shm

If nothing is displayed, continue. If you are concerned about making a direct database change, copy the SQLite files to another location while the app is closed before proceeding.

Add the trigger and verify the result after restarting

First, run a quick integrity check:

sqlite3 -readonly ~/.codex/logs_2.sqlite \
'PRAGMA quick_check;'

After confirming that it prints ok, add the trigger:

sqlite3 ~/.codex/logs_2.sqlite \
'CREATE TRIGGER IF NOT EXISTS block_log_inserts
 BEFORE INSERT ON logs
 BEGIN
   SELECT RAISE(IGNORE);
 END;'

Confirm that it exists:

sqlite3 -readonly ~/.codex/logs_2.sqlite \
"SELECT name FROM sqlite_master
 WHERE type='trigger'
 AND name='block_log_inserts';"

Restart Codex, perform normal work, and check whether the maximum log ID changes:

before_id=$(sqlite3 -readonly ~/.codex/logs_2.sqlite \
  'SELECT COALESCE(MAX(id),0) FROM logs;')

sleep 30

after_id=$(sqlite3 -readonly ~/.codex/logs_2.sqlite \
  'SELECT COALESCE(MAX(id),0) FROM logs;')

printf 'before=%s after=%s\n' "$before_id" "$after_id"

In my environment, I confirmed that one trigger existed and measured for 15 seconds after restarting Codex. The maximum log ID was 72683686 both before and after the measurement, so no new log rows were added.

However, the WAL file’s modification time changed. The precise conclusion is that the large stream of TRACE rows stopped, not that all SQLite-related I/O became zero.

How to undo it, and when not to use this workaround

Quit every Codex-related process again, then run:

sqlite3 ~/.codex/logs_2.sqlite \
'DROP TRIGGER IF EXISTS block_log_inserts;'

Because diagnostic logs are no longer saved while the trigger is active, remove it before using /feedback or submitting logs for troubleshooting. This is not an official OpenAI setting, so its behavior and support are not guaranteed.

An update to Codex or recreation of the diagnostic database may also remove the trigger. Check for it again after updating Codex.

Do not apply this trigger to state_5.sqlite, goals_1.sqlite, or session-related databases. Do not make the entire .codex directory read-only, and do not run VACUUM without understanding the impact. VACUUM rewrites the whole database and can create another large burst of writes.

Summary

The Codex SSD write issue may be caused by large TRACE-level diagnostic records being saved at a high rate in the SQLite log database, increasing write volume and database size. In my environment, I observed about 32 new rows per second and was able to stop new log rows with an unofficial SQLite trigger.

This is only an emergency workaround until an official fix is available. Remove it when diagnostic logs are needed, and be careful to modify only the intended database. Before deciding, first confirm that your own environment is actually experiencing the problem with lsof, quick_check, and a before-and-after log-ID comparison.

Search this site