[macOS Desktop 26.721.41059] Persistent SQLite TRACE churn remains in bundled 0.146.0-alpha.3.1

Open 💬 6 comments Opened Jul 25, 2026 by naifuliang
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

ChatGPT/Codex Desktop 26.721.41059 (build 5848), with bundled codex-cli 0.146.0-alpha.3.1.

What subscription do you have?

ChatGPT subscription. The exact tier does not appear relevant to this local app-server logging issue.

What platform is your computer?

Darwin 27.0.0 arm64 arm

macOS 27.0 (26A5378n), Apple Silicon.

What issue are you seeing?

The latest ChatGPT/Codex Desktop build available on this Mac still persisted high-frequency TRACE/DEBUG events to ~/.codex/logs_2.sqlite during ordinary active Codex use, producing measurable app-server disk writes and SQLite insert/prune churn.

Aggregate-only measurements collected before applying any workaround:

  • logs_2.sqlite: 380,895,232 bytes
  • logs_2.sqlite-wal: 4,630,912 bytes
  • retained rows: approximately 30,000
  • sqlite_sequence for logs: approximately 30.23 million
  • PRAGMA page_count: 92,992
  • PRAGMA freelist_count: approximately 80,000 (about 86% of pages)
  • a 50-second active sample advanced the sequence by 2,125 IDs, approximately 42.5 inserts/second
  • a separate 30-second sample advanced it by 1,042 IDs, approximately 34.7 inserts/second
  • in the latter sample, the bundled codex app-server wrote 14,462,976 bytes according to macOS proc_pid_rusage(RUSAGE_INFO_V4); the ChatGPT parent process wrote another 2,556,864 bytes
  • a more active 30-second window showed 43,909,120 bytes written by the app-server

The retained database was dominated by persistent diagnostic logging:

TRACE  16,484 rows  ~26.01 MiB estimated
INFO    8,364 rows   ~5.54 MiB estimated
DEBUG   5,477 rows   ~4.30 MiB estimated
WARN      858 rows   ~0.48 MiB estimated
ERROR     152 rows   ~0.04 MiB estimated

The highest-volume current targets included:

codex_api::sse::responses                         TRACE
codex_app_server::outgoing_message                TRACE
codex_mcp::connection_manager                     TRACE
codex_core::stream_events_utils                   DEBUG
codex_http_client::transport                      TRACE

This does not look like legacy file bloat alone. The high sequence value versus retained rows, the approximately 86% freelist, and the live sequence deltas show ongoing insert-and-prune churn. The process-level write counters confirm real disk writes, although those counters also include other app-server state files.

The current source still appears to configure the persistent SQLite layer with default_filter() whose default is LevelFilter::TRACE, plus a target denylist. RUST_LOG applies to the stderr formatting layer and does not provide a supported way to lower or disable the SQLite sink.

I did not inspect or attach raw feedback_log_body values because they may contain private task content, local paths, or identifiers.

What steps can reproduce the bug?

  1. Run ChatGPT/Codex Desktop 26.721.41059 on macOS with no insert-blocking trigger on the logs table.
  2. Start an active Codex task that streams responses and uses tools or subagents.
  3. In another terminal, record aggregate counters:
sqlite3 -readonly ~/.codex/logs_2.sqlite \
  "SELECT (SELECT seq FROM sqlite_sequence WHERE name='logs'),
          COUNT(*),
          COALESCE(SUM(estimated_bytes), 0)
   FROM logs;"
  1. Repeat after 30-60 seconds. The sequence advances by roughly 35-42 IDs/second in the observed active windows, while retained-row growth is much smaller because old rows are pruned.
  2. Inspect aggregate levels and targets:
sqlite3 -readonly ~/.codex/logs_2.sqlite \
  "SELECT level, COUNT(*), SUM(estimated_bytes)
   FROM logs GROUP BY level ORDER BY COUNT(*) DESC;"
  1. Confirm with lsof that the bundled codex app-server holds logs_2.sqlite, -wal, and -shm open for writing.

As an A/B confirmation, I later installed the community workaround:

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

With the app reopened and actively used, four samples across 30 seconds then showed:

  • sequence unchanged at 30,252,096
  • retained row count unchanged at 32,393
  • WAL unchanged at 8,272 bytes
  • database and WAL modification times unchanged

This strongly isolates the persistent logs insert path as the source of the observed SQLite churn. The trigger is only a local stopgap and disables persistent diagnostics.

What is the expected behavior?

Normal production Desktop use should not persist per-event SSE, outgoing-message, networking, and tool-stream TRACE/DEBUG records to SQLite by default.

The persistent SQLite sink should:

  • default to INFO or WARN rather than TRACE;
  • provide a documented setting to disable or control persistent diagnostic logging;
  • enforce a bounded DB/WAL byte budget and write-rate protection;
  • avoid insert-then-delete churn for high-frequency events;
  • provide a supported compaction/rotation command for existing bloated databases.

Additional information

Related reports:

  • #28224 was closed as fixed, with a maintainer asking users who still see excessive writes to open a new bug report.
  • #17320 remains open and documents the SQLite sink ignoring RUST_LOG.
  • #30236 contains earlier Desktop reproductions, including bundled 0.146.0 alpha builds.
  • #35092 documents residual per-SSE TRACE persistence in 0.145.0 and newer builds.

The earlier fixes substantially reduced the original catastrophic write rate, but this latest Desktop build still shows persistent TRACE-default policy and measurable write amplification. This report does not claim proven SSD failure or extrapolate the short active samples to a full year.

View original on GitHub ↗

6 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #35092
  • #35269

Powered by Codex Action

naifuliang · 1 month ago

Thanks — I reviewed both suggestions.

  • #35092 is the closest technical match: it tracks the same residual per-SSE TRACE persistence in the SQLite sink on 0.145+ builds, including macOS Desktop confirmations.
  • #35269 uses the same Desktop build as this report, but it primarily tracks broader long-session memory, renderer, helper-process, and resource-retention behavior.

This report adds a controlled aggregate-only A/B on Desktop 26.721.41059 / bundled 0.146.0-alpha.3.1:

  • without mitigation: approximately 34.7–42.5 SQLite log inserts/second during active windows, with 14.5–43.9 MB written by the app-server per 30-second sample;
  • with the insert-blocking trigger: no sequence, row-count, WAL-size, or mtime movement across a 30-second active sample.

I opened a new report because the maintainer closing #28224 explicitly asked users who still observe excessive writes to provide a new bug report with details. I am happy for maintainers to deduplicate or close this in favor of #35092; the main value here is the latest exact Desktop build plus the before/after measurements.

anotherpanacea-eng · 1 month ago

Independent read-only reproduction on ChatGPT/Codex Desktop 26.721.41059 (build 5848), bundled codex-cli 0.146.0-alpha.3.1, macOS 27.0 arm64.

Aggregate measurements taken 2026-07-26 EDT, before applying any workaround:

  • ~/.codex/logs_2.sqlite: 762,511,360 bytes
  • retained rows: 403,285
  • sqlite_sequence for logs: 85,873,999
  • during a synchronized 30-second active sample, the sequence advanced to 85,874,255 (+256, ~8.5 inserts/sec) while retained rows stayed unchanged at 403,285
  • macOS proc_pid_rusage(RUSAGE_INFO_V4) over the same interval recorded 8,253,440 bytes written by the bundled Codex process and 2,088,960 bytes by the ChatGPT parent (10,342,400 bytes combined); these counters include all process writes, not only this database
  • the largest retained target/level pair was codex_api::sse::responses | TRACE (134,744 rows; 145,410,632 estimated bytes)

The rate in this window was lower than the samples in the issue body, but the unchanged retained-row count alongside the advancing sequence independently reproduces ongoing insert/prune churn on the same current Desktop build.

I did not inspect or attach raw feedback_log_body values.

jcmsj · 1 month ago

Confirmed on another Apple Silicon Mac with the renamed ChatGPT app (bundle id com.openai.codex), version 26.721.41059 / build 5848, macOS 27.0.

Before mitigation, ~/.codex/logs_2.sqlite contained 50,276 retained rows (26,040 TRACE; 12,475 DEBUG) and an estimated 58.38 MB of retained log payload. During a short active sample the sqlite_sequence value increased from 328,228 to 328,601: 373 inserts in roughly 30 seconds (~12.4/s).

I applied the workaround described here:

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

Afterward, with the app still active, the sequence, row count, and estimated bytes remained unchanged (329,869 / 50,385 / 58,388,099) across a further sample. This cleanly stopped the SQLite insert churn locally. Normal Codex use continues, but persistent diagnostic logging is disabled, so this is only a mitigation—not a product fix.

PS: definitely less heat felt around my macbook air

aqiuya025 · 23 days ago

I can corroborate this on Windows 10 22H2 (build 19045, x64) with a newer Codex Desktop package.

Environment:

  • Codex Desktop package: 26.727.6591.0
  • Locally detected official App Server: 0.146.0-alpha.9.2
  • SQLite trigger count: none added; no mitigation trigger was used
  • Measurement was aggregate-only and read-only (mode=ro + PRAGMA query_only)
  • No log bodies, prompts, outputs, credentials, account identifiers, thread IDs, or user paths were read or shared

Read-only sample:

  • Window: 216.742 seconds (about 3.61 minutes)
  • MAX(id): 11,549,628 -> 11,549,934 (+306, about 84.7 IDs/minute)
  • Retained row count: 39,357 -> 39,357 (no net change)
  • All 306 IDs inserted during the window were still present at T1, so the unchanged retained count implies approximately 306 older rows were pruned during the same window

Levels among the 306 new retained rows:

  • TRACE: 219 (71.6%)
  • INFO: 48 (15.7%)
  • DEBUG: 39 (12.7%)

Highest-volume targets:

  • codex_app_server::outgoing_message: 118
  • codex_api::sse::responses: 85
  • codex_core::stream_events_utils: 28
  • feedback_tags: 22
  • opentelemetry-otlp: 8
  • several other Codex targets: 7 or fewer each

Aggregate estimated persisted log bytes for those rows:

  • 193,205 bytes, about 53.5 KiB/minute of estimated row content

File observations:

  • logs_2.sqlite: 95,199,232 bytes -> unchanged
  • logs_2.sqlite-wal: 3,530,872 -> 4,173,592 bytes (+642,720 bytes)
  • logs_2.sqlite-shm: 32,768 bytes -> unchanged
  • WAL mtime advanced throughout the sample
  • A separate Windows Resource Monitor snapshot showed active writes to both logs_2.sqlite-wal and state_5.sqlite-wal; the instantaneous values are not used as the primary measurement here

This reproduces the same insert-and-prune churn on Windows: the base DB and retained row count can remain flat while IDs advance and the WAL keeps changing. The current dominant targets are per-message/per-SSE tracing rather than the older bridged target=log noise.

I am not claiming proven SSD damage or attributing an audible mechanical-disk sound to this SQLite activity; the Codex state directory in this reproduction is on an SSD. The actionable issue is avoidable persistent TRACE write amplification and the lack of a documented, supported control for the SQLite log sink.

Requested direction:

  • filter or sample high-frequency codex_api::sse::responses and codex_app_server::outgoing_message TRACE events before SQLite insertion;
  • expose a supported SQLite log-level/retention control;
  • avoid requiring users to add unsupported SQLite triggers that may interfere with batched inserts, diagnostics, or future migrations.
YunyueLi · 6 days ago

Follow-up reproduction on a newer macOS Desktop build, after the SQLite logging mitigations shipped through the 0.148/0.149 line.

Environment:

  • macOS 26.5 (25F71), Apple Silicon arm64
  • ChatGPT/Codex Desktop 26.818.31338 (build 6892)
  • bundled codex-cli 0.149.0-alpha.4
  • sample captured 2026-08-21 CST
  • no log bodies, prompts, outputs, credentials, thread IDs, or user paths were inspected or shared

Controlled A/B method:

  1. Confirmed the local BEFORE INSERT ON logs ... RAISE(IGNORE) mitigation trigger was active.
  2. Ran PRAGMA wal_checkpoint(TRUNCATE).
  3. Temporarily removed the trigger for a 15-second active Desktop sample.
  4. Restored the trigger automatically and truncated the WAL again.
  5. Verified aggregate counters for another 15 seconds with the trigger restored.

Results with the trigger temporarily disabled:

  • 136 rows persisted in 15 seconds
  • TRACE: 77 rows (56.6%), 22,713 estimated bytes
  • DEBUG: 30 rows, 28,146 estimated bytes
  • INFO: 28 rows, 35,334 estimated bytes
  • WARN: 1 row, 452 estimated bytes
  • the rows appeared as a single batch at approximately t=8 seconds
  • WAL size was 4,152 bytes at t=0 after the trigger DDL and reached 230,752 bytes when the batch landed (+226,600 bytes)

TRACE targets in that batch:

codex_app_server::outgoing_message   59
codex_app_server::message_processor   5
codex_keyring_store                   4
codex_core::exec_policy               4
codex_core::session::world_state      3
codex_core::session::turn             1
codex_core::client                    1

After restoring the trigger and truncating the WAL, a further 15-second active sample showed:

  • retained row count unchanged at 136
  • MAX(id) unchanged at 42,767,635
  • maximum TRACE id unchanged at 42,767,635
  • WAL remained at 0 bytes

This suggests the newer build has changed the write shape from frequent small commits to a roughly 8-second batch in this short sample, but it has not eliminated persistent TRACE/WAL activity. The dominant residual source here is now codex_app_server::outgoing_message, rather than the HTTP/SSE/WebSocket targets addressed by recent filtering changes.

This appears consistent with the broader root-cause discussion in #31542, while adding a post-0.148/0.149 macOS data point. A supported persistent-SQLite log-level/disable control, or filtering/sampling codex_app_server::outgoing_message before insertion, would avoid requiring an unsupported schema trigger.

I am not extrapolating this short active sample to annual SSD wear; the actionable observation is that the SQLite sink still performs avoidable TRACE persistence and WAL writes during normal active use.