[Windows Desktop] Hidden subagent threads remain archived=0 and accumulate in state_5.sqlite

Open 💬 1 comment Opened Aug 26, 2026 by MisterRound
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

Codex Desktop creates internal rows with thread_source='subagent', but completed subagent rows can remain archived=0 indefinitely. They are hidden from the normal thread UI and have no user event, yet remain in the active portion of state_5.sqlite.

In one long-lived Windows Desktop + WSL profile, this accumulated to more than 4,400 hidden active rows. An offline archival update reduced that population, but additional unarchived subagent rows appeared afterward, showing that the workaround is not durable.

Environment

  • Codex Desktop on Windows with the agent running in WSL
  • Observed across Desktop-managed CLI versions from the 0.129 through 0.142 series
  • SQLite state store: %USERPROFILE%\.codex\state_5.sqlite

The report intentionally omits thread IDs, rollout paths, working directories, titles, prompts, repository details, and database files.

Confirmed database observations

This aggregate query is sufficient to expose the condition:

SELECT archived, COUNT(*)
FROM threads
WHERE thread_source = 'subagent'
GROUP BY archived;

Before mitigation, the result was:

archived=0: more than 4,400
archived=1: 35

All sampled aggregate groups had has_user_event=0. The active rows had no corresponding visible user chat in the Desktop UI.

Additional checks confirmed that the rows were not merely transient entries from a currently running subagent: their creation times spanned weeks, while archived remained false and archived_at remained null.

Offline mitigation and recurrence

With Desktop fully closed, after backing up the database, the following update archived the stale internal rows:

BEGIN IMMEDIATE;
UPDATE threads
SET archived = 1,
    archived_at = CAST(strftime('%s', 'now') AS INTEGER)
WHERE archived = 0
  AND thread_source = 'subagent';
COMMIT;

The bulk update changed more than 4,400 rows. A later aggregate check found 23 newly created subagent rows still at archived=0, plus a small number of older active rows. This confirms recurrence after cleanup.

Direct database editing is not an appropriate product workaround and requires a fully closed app plus a backup; it is included only as lifecycle evidence.

Expected behavior

When an internal subagent reaches a terminal state, Desktop/app-server should do one of the following consistently:

  • mark its thread row archived and set archived_at;
  • remove it if subagent persistence is unnecessary; or
  • store it outside user-visible/active thread metadata paths.

Existing stale rows should receive a one-time migration or bounded cleanup.

Actual behavior and impact

  • Completed internal subagent rows remain archived=0.
  • The normal UI hides them, so users cannot inspect or archive them through supported controls.
  • The active thread table can grow by thousands of invisible rows.
  • This was discovered while investigating Desktop startup and thread-list latency. The lifecycle/storage bug is confirmed; I have not isolated a wall-clock benchmark proving how much latency these rows add.

Suggested regression coverage

  1. Create a parent thread that launches several subagents.
  2. Let every subagent reach a terminal state.
  3. Assert that no completed thread_source='subagent' row remains active indefinitely.
  4. Assert that active thread-list queries either exclude internal subagents at the SQL layer or operate on a bounded indexed set.
  5. Exercise cleanup across app restart and abrupt parent-thread termination.

View original on GitHub ↗

1 Comment

github-actions[bot] contributor · 1 day ago

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

  • #39814
  • #40803

Powered by Codex Action