Skip to content

app-server: feedback log sqlite (logs_N.sqlite) grows unbounded — ~0.75 GB/day, no retention/rotation #26374

Closed

Description

@2vanm

Summary

The app-server's internal feedback/telemetry log database ($CODEX_HOME/logs_<N>.sqlite) grows without bound — no retention, no rotation, no size cap. On a long-running headless deployment (app-server driven 24/7) it reached 9.8 GB in ~10 days (~0.75 GB/day) before we noticed and manually cleared it.

This is distinct from state_<N>.sqlite (actual thread/session state), which stays small and healthy (~106 MB).

Environment

  • codex-cli 0.132.0 (codex app-server --listen stdio://)
  • Linux x86_64 (musl vendor build), driven continuously by an automation host (frequent short sessions: heartbeats, scheduled jobs, chat).
  • CODEX_HOME set to a persistent dir.

Evidence

logs_<N>.sqlite has a single dominant table logs:

1,420,123 rows, ~9.4 GB used (10.47 GB file, 1.08 GB freelist)
schema: id, ts, ts_nanos, level, target, feedback_log_body, module_path, file, line, thread_id, process_uuid, estimated_bytes

Bytes by column — feedback_log_body dominates at 7.3 GB. By target:

 5.88 GB  n=314,237  codex_api::endpoint::responses_websocket   (TRACE)
 0.44 GB  n=329,301  codex_otel.log_only
 0.39 GB  n=324,112  codex_otel.trace_safe
 0.21 GB  n=215,142  codex_api::sse::responses
 0.21 GB  n=    453  codex_core::client

Level mix: 675,801 INFO + 614,236 TRACE + 73,883 WARN + 23,110 DEBUG + 7 ERROR.

The largest single rows are ~800 KB each — full op.dispatch.compact / op.dispatch.user_input_with_turn_context request/response payloads serialised verbatim into feedback_log_body.

Steady-state growth (one row of the per-day breakdown):

2026-05-26  140,239 rows  0.71 GB
2026-05-27  136,379 rows  0.72 GB
...
2026-06-03  139,209 rows  0.75 GB

The logs_<N> suffix appears to be a schema version, not a size-based rotation — within a version the table grows indefinitely. RUST_LOG does not appear to gate these sqlite writes (no EnvFilter hook found for the feedback-log layer), and the only "bounded" reference in the binary (bounded_feedback_logs AS (...)) is a read-side CTE used when assembling a feedback bundle, not a write-side cap.

Impact

  • ~0.75 GB/day ≈ 22 GB/month, ~270 GB/year of pure telemetry on disk for any long-lived app-server deployment.
  • Full prompt/response payloads (including large compaction turns) are persisted indefinitely on the local disk — also a data-retention concern.

Expected behaviour

The feedback log should be bounded by default — e.g. a max age and/or max size with automatic pruning/rotation (à la a rolling window), or an explicit CODEX_HOME/config setting to cap or disable it. Ideally TRACE-level full-payload dumps should not be persisted to the on-disk feedback DB by default.

Workaround

logs_<N>.sqlite* is safe to delete while the app-server is stopped — it is recreated empty on next start and only debug/feedback-bundle history is lost. But this requires manual intervention and downtime since the file is held open continuously.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    app-serverIssues involving app server protocol or interfaces
    on Jun 4, 2026
  2. github-actions commented on Jun 4, 2026

    @github-actions
    Contributor

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

    Powered by Codex Action

  3. KZ8589 commented on Jul 23, 2026

    @KZ8589

    Adding two measurements from a Windows machine, including one that argues against a causal
    link I had assumed myself.

    Environment

    • Windows 11 Pro (10.0.26100), 4 logical CPUs
    • Codex desktop app 0.145.0-alpha.30 (same behaviour on 0.144.0-alpha.4)
    • Codex CLI 0.144.4 (npm @openai/codex)
    • No size / rotation / log-volume option found in ~/.codex/config.toml

    1. Same unbounded growth, smaller scale

    ~/.codex/logs_2.sqlite reached 1,097.31 MB (verified by file size on disk) and kept growing
    across application restarts. Much smaller than the 9.8 GB in the opening report, but the same
    shape: no cap, no rotation, no setting I could find.

    The growth here coincided with a single long-running task that spawned 116 subagents directly
    over 6 days; agent thread limit reached occurred 25 times, and the database held 468 unclosed
    relations. Codex's own internal instrumentation reported log aggregation SQL at 18.7 s, DB
    connection acquisition at 8.55 s, and 33 s to write 963 TRACE entries — those three numbers are
    self-reported by Codex and I have not independently verified them. The only figure I verified
    myself is the file size.

    2. Measured: zero growth while idle

    I wanted to know whether idle clients drive this. On this machine several processes keep the
    Codex runtime open at once: one codex mcp-server per open Claude Code window, plus a codex
    process embedded in the ChatGPT desktop app.

    Measurement window: 116 minutes. Several idle codex clients at the start; the Codex app and
    ChatGPT were closed partway through, leaving one idle codex mcp-server; no tasks issued; no
    new session records written. Combined size of logs_2.sqlite, its -wal and its -shm was
    6,492,072 bytes at both ends — a delta of exactly 0 over the whole window, which spanned both
    configurations. Modification timestamps did advance, so the files are being touched, but no
    growth resulted.

    Caveat: a WAL reuses already-allocated space, so "size unchanged" is not the same as "no
    writes". What I can say is that idling did not grow the database.

    3. A/B test: quarantining the log DB did not reproduce a speed-up

    I moved logs_2.sqlite / -wal / -shm aside (nothing else changed) and ran the same fixed workload
    before and after: disposable working folder, 3 subagents launched in parallel, each asked only
    to run echo ok and summarise the result in 1-2 sentences; wall-clock from start until all
    three finished; identical prompt and command every run.

    • Before quarantine (n=3): median 53.76 s — runs 179.75 / 53.76 / 35.51
    • After quarantine (n=6): median 36.24 s — runs 37.52 / 47.45 / 33.83 / 28.70 / 37.35 / 35.13
    • No run exceeded 90 s after; before, 1 of 3 took ~180 s

    Against bands I registered before measuring (improved = median <= 27 s; same level = 35-55 s;
    worse = >= 90 s) this lands on "same level". So on this path I could not demonstrate that the
    1.1 GB database was what made things slow, even though the numbers did come down.

    Caveats, because they matter for how much weight this deserves:

    • measured with the CLI (0.144.4) while the symptom I was chasing is in the app (0.145.0-alpha.30)
    • 4 logical CPUs shared with other applications; CPU contention is not separated out
    • the test load (3 subagents, trivial work, ~40 s) is far lighter than the real symptom (many
      subagents, heavy work, long duration), so DB contention under heavy load is not ruled out
    • median 36.24 s sits close to the 35 s band edge

    I mention this because the performance reports (e.g. #29177) and this growth report tend to be
    read as one story. The growth is clearly real. The causal step from "large log DB" to "slow" is
    the part I could not confirm at light load, and I would rather post the negative result than
    leave the assumption unchallenged.

    Separate observation (not claimed as a defect)

    Each subagent also produces its own session record on disk: one run of the test above (parent
    plus 3 subagents) creates 4 records, so the 6 runs created 24, and this machine's sessions
    directory now totals about 1.7 GB across 1,285 records. I note it only as context for how
    expensive high fan-out is in stored records — that directory is my own work history, not a bug.

  4. etraut-openai commented on Oct 13, 2026

    @etraut-openai
    Contributor

    (response from codex)

    Thanks for quantifying the long-running headless logs growth. CLI 0.161.0 added automatic log retention in #49425: it prunes by age and occupied database size at startup and periodically thereafter. SQLite may keep freed pages in the file for reuse, so file size alone need not fall. Closing the no-retention report as addressed; high logging I/O or verbosity on a current release should be reported separately with measurements.

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

    CLIIssues related to the Codex CLIapp-serverIssues involving app server protocol or interfacesbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions