Skip to content

Windows Codex app continuously writes high-volume TRACE websocket logs to ~/.codex/logs_2.sqlite despite RUST_LOG=warn #29463

Description

@LeoZhu1999

Summary

On Windows, Codex Desktop continuously writes high-frequency TRACE logs into ~/.codex/logs_2.sqlite, mainly from websocket/tungstenite internals, even though RUST_LOG=warn and analytics/OTel export are disabled in ~/.codex/config.toml.

This causes persistent SQLite/WAL writes and database growth.

Environment

  • OS: Windows
  • Codex app package: OpenAI.Codex_26.616.6631.0_x64__2p2nqsd0c76g0
  • Codex app-server process:
    • codex.exe app-server --analytics-default-enabled
  • Database:
    • C:\Users\<user>\.codex\logs_2.sqlite
    • WAL mode with logs_2.sqlite-wal

Relevant config

~/.codex/config.toml includes:

[analytics]
enabled = false

[otel]
exporter = "none"

Environment variable checks:

RUST_LOG Process = warn
RUST_LOG User    = unset
RUST_LOG Machine = unset

Observed behavior

After fully restarting Codex Desktop, logs_2.sqlite continues to receive high-frequency writes.

A 28-second sample after restart showed:

max(id) increased by 573
logs_2.sqlite-wal continued updating
row count stayed constant, indicating new rows are inserted while older rows are deleted

Recent 1000 inserted ids were dominated by:

TRACE log                                      839 rows
INFO  codex_otel.log_only                      41 rows
INFO  codex_otel.trace_safe                    40 rows
TRACE codex_api::endpoint::responses_websocket 40 rows
TRACE codex_api::sse::responses                40 rows

Latest TRACE log bodies include low-level websocket/tungstenite messages such as:

tokio-tungstenite ... compat.rs ... Read.with_context read -> poll_read
tokio-tungstenite ... lib.rs ... WebSocketStream.with_context
Parsed headers [...]
WouldBlock

Impact

  • Continuous disk writes to SQLite/WAL
  • logs_2.sqlite growth and churn
  • Extra local storage usage
  • Potential performance and SSD wear concern
  • TRACE-level logs may capture more detailed internal request/response metadata than expected

Before manual maintenance, the database was approximately:

logs_2.sqlite before VACUUM: 199,499,776 bytes
logs_2.sqlite after VACUUM:   75,206,656 bytes

After reopening Codex, WAL growth resumed:

logs_2.sqlite-wal around 5 MB and still updating

Expected behavior

With RUST_LOG=warn, [analytics].enabled = false, and [otel].exporter = "none", Codex should not continuously persist high-volume TRACE websocket/tungstenite logs to the local SQLite log store during normal use.

If local SQLite diagnostics intentionally retain TRACE records, there should be a documented configuration option to disable or reduce this verbosity.

Reproduction steps

  1. Start Codex Desktop on Windows.
  2. Ensure:
    • RUST_LOG=warn
    • [analytics].enabled = false
    • [otel].exporter = "none"
  3. Open or continue a Codex thread.
  4. Inspect ~/.codex/logs_2.sqlite and ~/.codex/logs_2.sqlite-wal.
  5. Sample max(id), level, target, and WAL modification time over 20-30 seconds.
  6. Observe continuous inserts of TRACE log, codex_api::endpoint::responses_websocket, and codex_api::sse::responses.

Notes

I avoided attaching the SQLite database directly because it may contain sensitive local diagnostic/session details.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    windows-osIssues related to Codex on Windows systems
    app-serverIssues involving app server protocol or interfaces
    configIssues involving config.toml, config keys, config merging, or config updates
    on Jun 22, 2026
  2. YancyWei commented on Jun 23, 2026

    @YancyWei

    Additional Windows reproduction / mitigation data from another Codex Desktop install.

    Environment:

    • OS: Windows
    • Log DB: C:\Users\Admin\.codex\logs_2.sqlite
    • Timezone: Asia/Shanghai
    • Observed on: 2026-06-23

    Observed state before mitigation:

    • logs_2.sqlite size: 753,307,648 bytes (~718 MiB)
    • logs_2.sqlite-wal existed and was updating
    • logs table retained row count: 67,214
    • MAX(id): advanced from 58,159,254 to 58,204,400 during investigation
    • Level counts in retained rows:
      • TRACE: 33,672, estimated bytes 69,385,610
      • INFO: 27,662, estimated bytes 37,341,429
      • DEBUG: 5,626, estimated bytes 7,687,324
      • WARN: 226
      • ERROR: 28

    Recent high-frequency sample:

    • Around 2026-06-23 12:10, one minute contained ~2,000 log rows, including ~1,499 TRACE rows.
    • Recent rows were dominated by websocket/tungstenite internals and frame parsing, including WouldBlock, Read.with_context, AllowStd.with_context, WebSocketStream.with_context, received websocket frames, parsed headers, opcodes, etc.

    Top retained targets by count included:

    • TRACE codex_api::endpoint::responses_websocket: 12,771 rows, estimated bytes 49,797,435
    • TRACE log: 10,515 rows
    • TRACE codex_mcp::connection_manager: 2,711 rows
    • TRACE hyper_util::client::legacy::pool: 2,652 rows
    • TRACE codex_api::sse::responses: 2,418 rows
    • INFO codex_otel.log_only: 13,225 rows
    • INFO codex_otel.trace_safe: 13,207 rows

    SQLite metadata:

    • journal_mode: wal
    • page_size: 4096
    • page_count: 183,913
    • freelist_count: 138,975

    The large freelist means the DB file stayed large after pruning/retention cleanup, so the retained row count substantially under-represents the write volume that already occurred.

    Temporary mitigation applied locally:

    1. Backed up logs_2.sqlite, logs_2.sqlite-wal, and logs_2.sqlite-shm.
    2. Added a local trigger to block further inserts into logs:
    CREATE TRIGGER IF NOT EXISTS codex_block_logs_insert
    BEFORE INSERT ON logs
    BEGIN
      SELECT RAISE(IGNORE);
    END;
    1. Ran PRAGMA wal_checkpoint(TRUNCATE).
    2. Sampled for ~21 seconds afterward.

    Post-mitigation sampling result:

    • MAX(id) stayed fixed at 58,204,400
    • retained row count stayed fixed at 67,214
    • logs_2.sqlite stayed fixed at 753,307,648 bytes
    • logs_2.sqlite-wal stayed fixed at 0 bytes

    This confirms the write churn was coming through logs inserts, and blocking that table stopped WAL growth on this machine. This workaround is obviously not ideal because it disables persisted logs, but it was needed to stop the local write churn.

  3. Qin202 commented on Jun 23, 2026

    @Qin202

    Confirmed independently on Windows with Codex Desktop 26.616.9593.0 (x64).

    Before cleanup:

    • logs_2.sqlite: 197,857,280 bytes
    • logs_2.sqlite-wal: 6,027,592 bytes
    • Retained rows: 7,310
    • Levels: TRACE 4,639 (63.5%), INFO 2,190, DEBUG 465, WARN 16
    • MAX(id): 22,467,668
    • SQLite freelist: 43,622 / 48,305 pages (~90.3%)

    During a 5-second sample, the retained row count stayed constant while MAX(id) increased by 44, confirming continuous insert/delete churn.

    RUST_LOG was already warn, with no trace/debug/sqlite override in config.toml. After deleting TRACE/DEBUG, running VACUUM, truncating the WAL, and persisting RUST_LOG=warn, TRACE/DEBUG immediately returned. During a subsequent 10-second sample, MAX(id) increased by 151.

    As a diagnostic workaround, a SQLite BEFORE INSERT trigger that ignored TRACE/DEBUG stopped those records completely; only one INFO record was added during the next 10-second sample. This suggests the high-volume records are being persisted upstream of, or independently from, the documented RUST_LOG filter.

    No database or raw log bodies are attached because they may contain sensitive session data.

  4. april-yc commented on Jun 24, 2026

    @april-yc

    I can reproduce this on Windows with a newer Codex Desktop package.

    Environment

    • OS: Windows
    • Codex package:
      OpenAI.Codex_26.616.9593.0_x64__2p2nqsd0c76g0
    • Codex executable:
      C:\Program Files\WindowsApps\OpenAI.Codex_26.616.9593.0_x64__2p2nqsd0c76g0\app\resources\codex.exe
    • Database:
      C:\Users\<redacted>\.codex\logs_2.sqlite
      C:\Users\<redacted>\.codex\logs_2.sqlite-wal

    Observed behavior

    The database is in WAL mode. The main database file size stays mostly unchanged, but logs_2.sqlite-wal continues to update while Codex is running.

    A read-only snapshot showed:

    • MAX(id) increased by 188 within 10 seconds.

    • Later, MAX(id) increased by another 155 within 25 seconds.

    • The total row count did not meaningfully increase, which suggests Codex may be inserting new log rows while pruning old rows.

    • In a recent 30-second window:

      • Around 09:30:02, there were about 2010 TRACE rows, with an estimated log-body size of about 1.33 MB.
      • Around 09:31:05, the recent 30-second window still contained about 1258 TRACE rows.
    • Recent one-hour write sources were dominated by:

      • TRACE log: 1041 rows
      • TRACE codex_api::sse::responses: 1003 rows
    • The latest log rows were almost all TRACE.

    • The associated process_uuid pointed to the currently running Codex process.

    Configuration

    I did not find any explicit TRACE, RUST_LOG, or log-level configuration in:

    C:\Users\<redacted>\.codex\config.toml

    Windows denied reading the full process command line, so I cannot confirm whether the log level is being set by the startup environment.

    Expected behavior

    Codex Desktop should not continuously persist high-frequency TRACE logs into the local SQLite log database during normal usage, especially when no TRACE-level logging is configured by the user.

    If persistent local diagnostic logging is intentional, there should be a documented option to reduce the SQLite log level or disable high-volume TRACE persistence.

  5. Yassycodes commented on Jun 25, 2026

    @Yassycodes

    Thanks for writing this up. I am seeing a related Windows Codex Desktop performance regression in #28855. My case started with a large logs_2.sqlite / WAL problem too, but even after rotating logs and reproducing with small fresh logs, Codex Desktop still caused intermittent mouse/typing/system input lag on Windows.

    I linked your report in a broader Discussion collecting recent Windows Desktop performance reports here: #29949 (comment)

    No action needed from you unless you want to add more detail there, but I wanted to connect the reports because the recent Windows performance issues look related enough that they may need a canonical tracker.

  6. denispol commented on Jun 25, 2026

    @denispol

    Expected: the SQLite sink builds its own Targets filter (hardcoded TRACE) and only the stderr layer honors RUST_LOG. Fix adds CODEX_LOG_DB_LEVEL (and [log] level) and lowers the default to INFO: https://github.com/denispol/codex/pull/1

  7. StellaTC commented on Jul 21, 2026

    @StellaTC

    I can reproduce this on Windows with Codex Desktop OpenAI.Codex_26.715.8383.0.

    A read-only 60.293-second sample after a full app restart showed:

    • 436 newly inserted rows by MAX(id)
    • 378 TRACE rows (86.7%, about 6.27 TRACE rows/sec)
    • about 2.52 MiB estimated TRACE payload
    • WAL net growth of 379,040 bytes
    • writes continued throughout the window, so this is not startup-only logging

    The dominant targets in a later 120-second sample were:

    • codex_api::sse::responses: 662 rows
    • codex_app_server::outgoing_message: 309 rows
    • codex_http_client::transport: 4 rows totaling about 2.38 MB

    The transport and SSE records can contain complete request JSON, conversation/tool arguments, and SSE event bodies. I did not attach the database because it contains sensitive local context.

    Source inspection agrees with the root-cause analysis in #31542: the SQLite sink has its own TRACE-default filter, while RUST_LOG=warn only limits terminal/stderr output. Restarting with RUST_LOG=warn therefore does not mitigate the SQLite writes.

    Could the maintainers please clarify:

    1. Is there an internal fix plan for this?
    2. Is there any currently undocumented environment variable or config option that can set the SQLite sink to warn or off?
    3. What is the intended design purpose and retention policy of this local SQLite collector?
    4. Could Codex provide a persistent option such as CODEX_SQLITE_LOG_LEVEL=warn|off, and avoid persisting full request/SSE payloads by default?

    Until there is a supported switch, users handling sensitive work cannot reliably prevent this content from being retained locally.

  8. DaveW001 commented on Jul 27, 2026

    @DaveW001

    Confirming this is still very much alive on Windows. I went into the database to find out what's actually burning the space, and it's almost entirely one source.

    logs_2.sqlite grew from ~15 MB to 619 MB in a single day — normal usage, nothing unusual. Inspected the table (~31k rows) and the breakdown was lopsided enough that a single module accounts for nearly all of it:

    target rows approx bytes
    codex_http_client::transport 1,567 ~610 MB
    everything else combined ~29,800 ~8 MB

    So roughly 99% of the growth is full HTTP request/response payloads logged at TRACE. Individual entries run 3 to 5 MB each. The remaining ~30k rows across all the normal debug and info targets add up to less than 8 MB combined.

    RUST_LOG=warn does nothing for this sink, confirming what others have reported. No config.toml setting I've found touches it.

    I ended up having to script a daily task that kills Codex, renames the SQLite files, and lets the app rebuild them empty. Works, but it's the kind of thing that shouldn't be necessary. Either respect the configured log level or at least give us a knob to disable transport-level payload logging. Right now there's no user-facing way to stop it.

    Lots of Windows users hitting this. Would really like to see it get traction.

  9. masteryyh commented on Jul 30, 2026

    @masteryyh

    Tell Codex to use SQLite Trigger to silently drops TRACE logs insertions, it works on my side

  10. enolaMM commented on Aug 12, 2026

    @enolaMM

    Confirmed on Windows with Codex Desktop package 26.803.10989.0 and bundled CLI 0.147.0-alpha.6.6.

    RUST_LOG=info was present in the spawned task environment, but logs_2.sqlite still received TRACE/DEBUG rows. In one 10-minute sample, the database recorded:

    • TRACE: 966 rows
    • DEBUG: 237 rows

    The WAL was actively updated. The peak observed second had 43 log rows, including 41 TRACE rows.

    This confirms the SQLite logger appears to bypass the standard Rust log filter in a newer Windows Desktop build as well. Please provide a supported setting to suppress or bound local SQLite TRACE/DEBUG persistence.

    No raw log database or session content is attached, because those may contain private data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesbugSomething isn't workingconfigIssues involving config.toml, config keys, config merging, or config updatesperformancewindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions