What version of the IDE extension are you using?
openai.chatgpt-26.406.31014-linux-x64 (VSCodium on Linux Mint)
What subscription do you have?
ChatGPT Plus
Which IDE are you using?
VSCodium (Code - OSS fork)
What platform is your computer?
Linux x64 (Linux Mint)
What issue are you seeing?
During model streaming responses, the Codex app-server binary writes ~5 MiB/s (observed up to ~16 MiB/s in iotop) to ~/.codex/logs_2.sqlite-wal. This results in sustained disk write rates that can significantly impact SSD longevity and system performance.
This issue is independent of the thread-stream-state-changed warning spam and the open-in-targets retry loop, which were investigated separately.
Root cause
The extension correctly sets RUST_LOG=warn when spawning the app-server process — confirmed via /proc/<pid>/environ:
However, the SQLite logging sink appears to bypass or not respect the RUST_LOG filter, since TRACE-level entries are still persisted to logs_2.sqlite despite RUST_LOG=warn. The SQLite logging path appears to operate outside of the standard RUST_LOG filtering mechanism, or uses a separate filter configuration.
This was confirmed via strace during streaming:
pwrite64(20</home/k/.codex/logs_2.sqlite-wal>, ..., 4096, ...) = 4096
pwrite64(20</home/k/.codex/logs_2.sqlite-wal>, ..., 4096, ...) = 4096
...
And via SQLite query — MAX(id) jumped by ~5000 rows for a single short (~50 token) response, while total row count remained stable, indicating that rows are being rapidly inserted and pruned/rotated during streaming:
-- Before response:
SELECT MAX(id), COUNT(*) FROM logs; --> 3088667 | 30141
-- After response:
SELECT MAX(id), COUNT(*) FROM logs; --> 3093673 | 30141
Log level breakdown in logs_2.sqlite:
TRACE 20485 (68%)
INFO 8286
DEBUG 1326
WARN 44
Sample TRACE entries written during streaming:
target=hyper_util::client::legacy::pool feedback_log_body="idle interval checking for expired"
target=log feedback_log_body="WouldBlock"
target=log feedback_log_body="/home/runner/work/codex/codex/.cargo-home/git/checkouts/tokio-tungstenite-..."
These are low-level internal network events from tokio-tungstenite and hyper_util with no diagnostic value for end users. They should not be persisted to disk in a production binary — and critically, they are not suppressed by RUST_LOG=warn as one would expect.
What steps can reproduce the bug?
- Open a workspace in VSCodium/VS Code with the Codex extension.
- Confirm
RUST_LOG=warn is set:
cat /proc/$(pgrep -f 'codex.*app-server')/environ | tr '\0' '\n' | grep RUST_LOG
- Run
strace -f -e trace=pwrite64 -p $(pgrep -f 'codex.*app-server') in a separate terminal.
- Ask any question in the Codex chat panel and observe streaming.
- Observe continuous
pwrite64 calls to logs_2.sqlite-wal at ~5 MiB/s despite RUST_LOG=warn.
Alternatively, check log level distribution after a session:
sqlite3 ~/.codex/logs_2.sqlite "SELECT level, COUNT(*) FROM logs GROUP BY level ORDER BY COUNT(*) DESC"
What is the expected behavior?
RUST_LOG=warn should suppress TRACE and DEBUG output everywhere, including the SQLite logging sink. The current behavior — where RUST_LOG=warn suppresses stderr output but does not affect SQLite persistence — is inconsistent and undocumented.
TRACE-level events from internal networking libraries (tokio-tungstenite, hyper_util) should never be written to the persistent SQLite log database during normal operation.
Additional information
Suggested fix
The SQLite logging sink in app-server should apply the same log-level filter as RUST_LOG (or the internal tracing subscriber filter), rather than maintaining a separate or hardcoded verbosity level. The fix should ensure that setting RUST_LOG=warn — as the extension already does — is sufficient to suppress TRACE/DEBUG writes to logs_2.sqlite.
Workaround
Users can redirect logs_2.sqlite to tmpfs to protect their SSD while waiting for a fix:
# stop VSCodium first
mv ~/.codex/logs_2.sqlite ~/.codex/logs_2.sqlite.bak
ln -s /tmp/logs_2.sqlite ~/.codex/logs_2.sqlite
Note: logs_2.sqlite contains only internal diagnostic logs — no conversation history — so data loss on reboot is acceptable.
After symlinking logs_2.sqlite to tmpfs, disk I/O from the Codex extension dropped to zero during streaming, confirming that the SQLite WAL is the sole source of the observed write load.
Workaround 2: block inserts into the SQLite log table
Another workaround was suggested by @synap5e in this comment:
#17320 (comment)
Instead of redirecting logs_2.sqlite to tmpfs, users can prevent new rows from being inserted into the logs table by adding a SQLite trigger:
sqlite3 ~/.codex/logs_2.sqlite "CREATE TRIGGER IF NOT EXISTS block_log_inserts BEFORE INSERT ON logs BEGIN SELECT RAISE(IGNORE); END;"
This causes attempted inserts into the logs table to be ignored without returning an error to the application, which should prevent logs_2.sqlite-wal from growing due to persistent TRACE/DEBUG log writes.
To remove the workaround:
sqlite3 ~/.codex/logs_2.sqlite "DROP TRIGGER IF EXISTS block_log_inserts;"
As with the tmpfs workaround, this is not a proper fix. It disables local persistent logging rather than fixing the underlying issue: the SQLite logging sink appears to ignore RUST_LOG=warn and continues persisting TRACE/DEBUG entries during normal streaming.
What version of the IDE extension are you using?
openai.chatgpt-26.406.31014-linux-x64(VSCodium on Linux Mint)What subscription do you have?
ChatGPT Plus
Which IDE are you using?
VSCodium (Code - OSS fork)
What platform is your computer?
Linux x64 (Linux Mint)
What issue are you seeing?
During model streaming responses, the Codex
app-serverbinary writes ~5 MiB/s (observed up to ~16 MiB/s iniotop) to~/.codex/logs_2.sqlite-wal. This results in sustained disk write rates that can significantly impact SSD longevity and system performance.This issue is independent of the
thread-stream-state-changedwarning spam and theopen-in-targetsretry loop, which were investigated separately.Root cause
The extension correctly sets
RUST_LOG=warnwhen spawning theapp-serverprocess — confirmed via/proc/<pid>/environ:However, the SQLite logging sink appears to bypass or not respect the
RUST_LOGfilter, since TRACE-level entries are still persisted tologs_2.sqlitedespiteRUST_LOG=warn. The SQLite logging path appears to operate outside of the standardRUST_LOGfiltering mechanism, or uses a separate filter configuration.This was confirmed via
straceduring streaming:And via SQLite query — MAX(id) jumped by ~5000 rows for a single short (~50 token) response, while total row count remained stable, indicating that rows are being rapidly inserted and pruned/rotated during streaming:
Log level breakdown in
logs_2.sqlite:Sample TRACE entries written during streaming:
These are low-level internal network events from
tokio-tungsteniteandhyper_utilwith no diagnostic value for end users. They should not be persisted to disk in a production binary — and critically, they are not suppressed byRUST_LOG=warnas one would expect.What steps can reproduce the bug?
RUST_LOG=warnis set:strace -f -e trace=pwrite64 -p $(pgrep -f 'codex.*app-server')in a separate terminal.pwrite64calls tologs_2.sqlite-walat ~5 MiB/s despiteRUST_LOG=warn.Alternatively, check log level distribution after a session:
What is the expected behavior?
RUST_LOG=warnshould suppress TRACE and DEBUG output everywhere, including the SQLite logging sink. The current behavior — whereRUST_LOG=warnsuppresses stderr output but does not affect SQLite persistence — is inconsistent and undocumented.TRACE-level events from internal networking libraries (
tokio-tungstenite,hyper_util) should never be written to the persistent SQLite log database during normal operation.Additional information
Suggested fix
The SQLite logging sink in
app-servershould apply the same log-level filter asRUST_LOG(or the internaltracingsubscriber filter), rather than maintaining a separate or hardcoded verbosity level. The fix should ensure that settingRUST_LOG=warn— as the extension already does — is sufficient to suppress TRACE/DEBUG writes tologs_2.sqlite.Workaround
Users can redirect
logs_2.sqliteto tmpfs to protect their SSD while waiting for a fix:Note:
logs_2.sqlitecontains only internal diagnostic logs — no conversation history — so data loss on reboot is acceptable.After symlinking logs_2.sqlite to tmpfs, disk I/O from the Codex extension dropped to zero during streaming, confirming that the SQLite WAL is the sole source of the observed write load.
Workaround 2: block inserts into the SQLite log table
Another workaround was suggested by @synap5e in this comment:
#17320 (comment)
Instead of redirecting
logs_2.sqliteto tmpfs, users can prevent new rows from being inserted into thelogstable by adding a SQLite trigger:This causes attempted inserts into the logs table to be ignored without returning an error to the application, which should prevent logs_2.sqlite-wal from growing due to persistent TRACE/DEBUG log writes.
To remove the workaround:
As with the tmpfs workaround, this is not a proper fix. It disables local persistent logging rather than fixing the underlying issue: the SQLite logging sink appears to ignore RUST_LOG=warn and continues persisting TRACE/DEBUG entries during normal streaming.