Skip to content

Remote Control: threads viewed in the iOS app stay locked in the daemon, desktop fails with "already has an active writer" #44449

Open

Description

@lucharo

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

26.901.20858 (macOS), embedded app-server 0.153.x; Remote Control daemon codex app-server --remote-control 0.153.1; terminal CLI 0.153.4.

What subscription do you have?

ChatGPT Pro

What platform is your computer?

macOS 26.2 (25C56), Apple Silicon

What issue are you seeing?

Threads that I last opened in the ChatGPT iOS app (Codex tab, Remote Control) become unopenable in the Codex desktop app on the same Mac. Clicking them in the sidebar fails with:

thread 01a0831e-aec8-77c2-9295-7beeddf97692 already has an active writer

The desktop shows the thread as open elsewhere. Nothing is visibly open on the phone; the app is in the background. The model picker on those threads is also disabled, so they cannot be moved from GPT-5.6 Sol to GPT-6 Astra until the lock clears.

The cause is visible in logs_2.sqlite. When the iOS client (codex_chatgpt_ios_remote 1.2026.237) reconnects, the backend sends __slingshot_backend_notification_thread_resume__ for every thread the phone had touched, and the Remote Control daemon resumes all of them. Each resumed thread takes a writer lock in ~/.codex/thread-writer-locks/<thread>.lock. The desktop's own app-server then cannot resume them until the daemon tears the threads down, which happened about 50 minutes later.

Timeline from one occurrence (UTC, 2026-09-09):

20:35:23-20:35:26  daemon (pid 40273): 8 thread/resume requests, request_id
                   __slingshot_backend_notification_thread_resume__:<id>, connection 556
                   threads incl. 01a0802c…, 019fce14…, 019feb04…, 01a0831e…
21:07:50           desktop app-server: thread/resume 01a0831e… -> -32600 already has an active writer
21:08:23-21:13:01  same for 019fce14… (12 attempts)
21:23:55-21:26:23  same for 01a0802c… (8 attempts)
21:28:24           daemon: "clearing thread listener during thread-state teardown" for all three,
                   op: Shutdown, "Agent loop exited"; desktop can open them again

lsof on ~/.codex/thread-writer-locks/ during the window showed only the desktop's app-server holding locks for threads it had itself opened. The failing threads' locks were held by the daemon process. No turn was running in those threads on the phone.

What steps can reproduce the bug?

  1. Enable Remote Control in Codex desktop on a Mac.
  2. In the ChatGPT iOS app, open the Codex tab and view three or four threads hosted on that Mac. Background the app.
  3. Later, bring the iOS app back to the foreground (or let it reconnect).
  4. In Codex desktop on the Mac, click any of those threads in the sidebar.

Observed: already has an active writer, thread cannot be resumed or have its model changed. Waiting until the daemon tears the threads down (tens of minutes) clears it. Closing the Codex tab on the phone also clears it.

What is the expected behavior?

Viewing a thread on the phone should not lock it against the desktop on the machine that hosts it, at least while no turn is running. Either the daemon should release idle threads when the phone is backgrounded, or the desktop should be able to take the thread over from the daemon (or open it read-only, as #43253 did for the TUI) instead of failing.

Additional information

Related but different: #43374 and #44063 are stale locks left by an exited process. Here the lock holder is alive and legitimate; the problem is that a backgrounded phone client keeps every recently viewed thread loaded in the daemon. #43253 added a read-only fallback for the TUI only.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    app-serverIssues involving app server protocol or interfaces
    on Sep 10, 2026
  2. abruption commented on Sep 15, 2026

    @abruption

    I posted a concrete owner-cooperative release/handoff proposal in #45406: #45406 (comment). For this Remote Control case specifically, the proposed lifecycle rule is to unsubscribe on view close/background/disconnect, avoid resuming every recently viewed thread on reconnect, and release only after the owner proves the thread idle and flushes/shuts down its recorder. This preserves the native single-writer guarantee while preventing an idle remote viewer from blocking Desktop for tens of minutes.

  3. guayom commented on Sep 22, 2026

    @guayom

    Independent reproduction on the current desktop build: this still affects the iPad Remote flow.

    Environment

    • ChatGPT Desktop 26.915.31945 (build 9922)
    • macOS 15.6.1 (24G90)
    • ChatGPT Remote on iPad (mobile app version not captured)
    • Local Mac host through Remote Control

    Observed behavior

    1. Select a completed/idle local Codex thread from Remote on the iPad.
    2. The mobile client shows the thread title and host, but the body reports “Error loading messages” and “This task couldn't reconnect.” Another state reports “This is open in another app. Close it there to continue here.”
    3. The desktop app is displaying a different chat; the affected thread is not visibly open there.
    4. Desktop logs repeatedly show thread/resume from source=thread_hydration failing with code -32600: thread [redacted] already has an active writer.
    5. The affected thread remains notLoaded; its transcript is still readable and its recent turns are completed, so no turn appears to be running.

    Recovery attempted

    • Retried from the iPad.
    • Navigated away and closed the desktop window.
    • Fully quit and relaunched ChatGPT Desktop, producing a new desktop/app-server process.
    • Waited for Remote Control to reconnect and retried the thread.

    The failure persists after all of the above.

    Impact

    A specific completed thread cannot be loaded from iPad Remote or resumed normally despite no visible active turn. This appears consistent with the Remote Control daemon retaining writer ownership; restarting the desktop app alone does not release it.

    I can provide the full thread ID privately if maintainers need it.

  4. EasterFan commented on Sep 23, 2026

    @EasterFan

    I can reproduce the same issue on Android.

    Environment

    • ChatGPT for Android: 1.2026.258
    • ChatGPT for macOS: 26.915.31945 (build 9922)
    • Codex CLI: 0.155.1

    Steps to reproduce

    1. Start a Codex task on the Mac.
    2. Wait until the task has completed.
    3. Open the same session in ChatGPT for Android via Remote Control.
    4. The session remains stuck on an infinite loading screen.

    The task is already complete, but the session cannot be opened on the phone. The desktop side reports an active-writer conflict, even though no turn is running.

    This appears to be related to the remote client resuming a completed thread as an active writer instead of opening it in read-only mode or releasing ownership after the task finishes.

    Expected behavior

    The completed conversation should load normally on Android and allow the user to continue it, or show a clear handoff or reconnection message instead of loading indefinitely.

  5. shlomi98 commented on Oct 4, 2026

    @shlomi98

    I’m seeing the same issue with the Codex VS Code extension on Windows.

    My workflow:

    1. Start/work on a Codex task in VS Code.
    2. Leave VS Code and the task open.
    3. Open the same task from ChatGPT on iOS using Remote Control.
    4. iOS shows:

    "Another Codex session is using this task.
    Finish and close that session, then try again."

    This has been happening for several months across multiple Codex VS Code extension updates, so it does not appear to be a one-version regression.

    Claude Code Remote Control works correctly with the same general workflow: I can leave the desktop session running and continue controlling it remotely.

    For Codex, having to finish/close the desktop VS Code session before connecting from iOS defeats the purpose of Remote Control.

    Environment:

    • Windows
    • VS Code
    • Codex VS Code extension
    • ChatGPT iOS app
  6. Aragorn2046 commented on Oct 5, 2026

    @Aragorn2046

    Independent confirmation from another ChatGPT Pro / Codex Remote Control user.

    This is a significant regression in the Remote Control workflow for me. I previously used Remote Control specifically so that I could leave multiple Codex sessions running on my machines and freely inspect/steer those sessions remotely from the mobile app.

    Recently I increasingly get the equivalent of "this task is active elsewhere / close it there and try again here", forcing me to close or hand off sessions before I can control them remotely.

    That breaks the core Remote Control use case. The machine should be the execution plane and mobile/desktop clients should be interchangeable control surfaces. A session being open on its host should not prevent Remote Control from attaching to or steering it.

    The important behavioral regression from my perspective is:

    Previously:
    host session remains running → open mobile Remote Control → inspect/steer session → continue normally

    Now:
    host session remains running → open mobile Remote Control → session considered owned/active elsewhere → close/handoff required → then regain control

    Even if single-writer semantics are required internally, they should be invisible to the user. Remote needs either safe ownership transfer, an observer mode that can become writer when steering, or shared control semantics.

    Please restore the previous seamless Remote Control behavior. Requiring users to close sessions on the machine they are remotely controlling defeats much of the purpose of Remote Control.

  7. hqy117 commented on Oct 7, 2026

    @hqy117

    I’m seeing the same issue.

    Environment:

    • ChatGPT for iOS: 1.2026.224
    • VS Code: 1.140.0 (Universal)
    • Codex VS Code extension: 26.51002.51308
    • Remote host: Linux

    In my case, threads that I opened from Remote Control on iOS remained locked even after I disconnected Remote Control from the phone.

    After that, trying to open those same sessions from the VS Code extension failed with an "already has an active writer" error. Other sessions that had not been opened from iOS were still accessible normally.

    Reloading the VS Code window did not help.

    I checked the writer locks with:

    lsof ~/.codex/thread-writer-locks/*.lock
    

    and found that multiple threads were still being held by the same Codex Remote Control app-server process:

    codex -c features.code_mode_host=true app-server --listen unix://...
    

    The process had PPID 1 and continued running even after Remote Control had been disconnected on iOS.

    After killing that daemon process, all affected sessions immediately became accessible again from the VS Code extension.

    So this looks consistent with the Remote Control daemon retaining writer ownership for threads previously viewed on iOS, instead of releasing them when the mobile Remote Control session is disconnected.

    It would be very helpful to have either:

    1. automatic thread release when Remote Control disconnects, or
    2. an explicit per-thread "release/handoff" mechanism between Remote Control and the desktop/VS Code client.
  8. hqy117 commented on Oct 7, 2026

    @hqy117

    Additional observation / workaround:

    I tested the issue in both directions, and the writer lock appears to persist on whichever client opened the thread.

    Current workaround that consistently works for me:

    • iOS Remote Control opened the thread -> VS Code cannot open it:
      codex remote-control stop

    • VS Code opened the thread -> iOS Remote Control cannot open it:
      run Developer: Reload Window in VS Code

    Simply switching to another chat/session is not enough to release the thread on either side.

    So at least in my setup, this looks like a bidirectional thread ownership / writer-release issue rather than something specific to the iOS Remote Control daemon.

    A per-thread explicit "Release" / "Hand off" action would probably make this much easier to use without restarting either side.

  9. hosannasub commented on Oct 10, 2026

    @hosannasub

    Another Linux/iOS Remote reproduction, this time on Codex 0.160.0, with one additional observation that may help distinguish idle retention from a live ownership-tree problem.
    The affected app-server retained the parent thread plus several child/subagent writer locks. I sampled the corresponding rollout files over 15 seconds and found:

    • the top-level thread was still actively writing
    • one direct subagent was also actively writing
    • several sibling/other threads held writer locks but had zero rollout growth
      session_meta on the active child confirmed it was a depth-1 subagent of the affected top-level thread via parent_thread_id, forked_from_id, and thread_source: "subagent".
      So there appear to be at least two states in this bug family:
    1. idle threads retained by the Remote Control/app-server writer, as originally described here;
    2. an old app-server retaining an entire live parent + subagent execution tree across reconnect/handoff.
      In the second state, killing only lock files would be unsafe because the owning process is still legitimately writing. My recovery was to identify the exact app-server owning the execution tree, verify which of its threads were actually changing, terminate that app-server, verify the parent rollout froze cleanly, then fork from the latest persisted parent.
      SIGTERM did not terminate the old app-server in this occurrence; SIGKILL was required.
      After termination, the writer lock released immediately and the persisted JSONL remained valid.
      This makes me think the fix may need to address owner lifecycle and handoff at the app-server/execution-tree level, not only release idle threads on mobile background/disconnect.
      Environment:
      codex-cli / app-server 0.160.0
      Linux remote host with ChatGPT iOS Remote / SSH workflow.
  10. jaeilnet commented on Oct 13, 2026

    @jaeilnet

    I encountered a similar issue on 2026-10-13. Adding diagnostic evidence from this occurrence.

    Environment

    • macOS 15.5 (24F74), Apple Silicon
    • Desktop app release reported in logs: 26.1007.30912 (running from ChatGPT.app)
    • Standalone Codex CLI / managed app-server daemon: 0.162.1
    • A separate desktop app-server and a managed Remote Control daemon were running on the same Mac.
    • Mobile OS and mobile app version were not captured.

    Observed behavior

    Two conversations that I had been using from mobile later became inaccessible, with a message indicating that they were in use in another session. The exact original UI error text was not captured, so this is a paraphrase.

    Affected thread IDs:

    • 01a1337c-c900-7082-9998-604f058500d1
    • 01a133a3-61be-78c1-a258-b2fcc1644329

    Both threads appeared as notLoaded through the desktop app tools. Their latest recorded turns were completed, and their histories could still be read through thread/read.

    However, lsof showed that a separate live managed daemon held both thread writer lock files and both rollout files:

    PID 99487: codex app-server --remote-control --listen unix:// --analytics-default-enabled --managed-daemon
    ~/.codex/thread-writer-locks/01a1337c-c900-7082-9998-604f058500d1.lock
    ~/.codex/thread-writer-locks/01a133a3-61be-78c1-a258-b2fcc1644329.lock
    

    The latest recorded task completion timestamps were:

    01a1337c…  2026-10-13T07:58:01.257Z  task_complete
    01a133a3…  2026-10-13T07:52:34.974Z  task_complete
    

    Recovery attempts and results

    1. Checked the last task lifecycle events in all rollout files held by this daemon; each ended with task_complete.
    2. Ran codex app-server daemon restart. The command succeeded, replacing PID 99487 with PID 93528.
    3. Immediately checked with lsof: the new daemon had acquired both affected thread lock files again. Restarting alone therefore did not clear the observed lock ownership.
    4. Ran codex app-server daemon stop.
    5. Verified with lsof that neither affected lock file had an open owner afterward. No conversation histories or lock files were deleted.

    Successful reopening from mobile has not yet been confirmed. These observations establish live daemon ownership and reacquisition after restart; they do not establish which reconnect/subscription event caused it. We did not capture the backend resume notifications described in the original report.

    It would help if idle thread ownership could be released or handed off automatically, and if the inaccessible-thread UI identified the owning backend and provided a safe recovery action without requiring users to stop the entire daemon.

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 workingremote

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions