Skip to content

New sessions can't be created: git fetch during worktree init deadlocks on the fsmonitor daemon → "git command timed out after 60 seconds" #4105

Description

@brian-thomas-hpe

Short summary

New sessions can't be created: git fetch during worktree init deadlocks on the fsmonitor daemon → "git command timed out after 60 seconds"

Affected version or release

1.1.23 (regression introduced in 1.1.12; also reproduced on 1.1.16 and 1.1.22)

Installation context

macOS desktop app, single-user local install. Affects a normal clone that has core.fsmonitor=true and feature.manyFiles set. Copilot CLI 1.0.87-0 (bundled with app 1.1.23), Bundled git: 2.53.0-4 (the -4 build; system git is 2.98.0), Mac: M3 Pro macOS Sequoia 15.7.7

What happened?

Since v1.1.12, creating a new session fails with:

Session '' workspace initialization failed: git command timed out after 60 seconds

The worktree is never created, so no session is produced. It persists across app restarts and across the two updates I applied today (1.1.16 → 1.1.22 → 1.1.23). Deleting ~12 stale sessions did not help.

Root cause: during init the app runs (env-injected; no -c core.fsmonitor= in the argv):

git -C fetch --progress --no-write-fetch-head origin +refs/heads/:refs/remotes/origin/

With core.fsmonitor effectively on, the fetch spawns/attaches a git fsmonitor--daemon that inherits the fetch's --progress stderr write-end and never closes it. The parent holds the read-end waiting for progress; because the daemon keeps the write-end open, the pipe never reaches EOF. The watchdog sees received_output=false and kills at idle_timeout_secs=60.

This looks like the same defect as #3980 (empty core.fsmonitor override treated as "missing" at a serialization boundary, so fsmonitor stays on) surfacing on the session-creation path. My captured fetch argv carries no core.fsmonitor override at all.

Steps to reproduce

  1. Use a clone with core.fsmonitor=true and feature.manyFiles set.
  2. Create a new session (worktree-backed) in that project.
  3. Observe init hang ~60s, then "git command timed out after 60 seconds"; no session created.

Reproduced outside the app with a standalone harness that mimics the fetch (parent holds the stderr pipe read-end while running git fetch --progress):

  • core.fsmonitor=false → pipe hits EOF in ~2s, fetch exits cleanly.
  • core.fsmonitor=true → no EOF, fetch stays alive indefinitely = deadlock.
    Reproduces identically on both bundled git builds (2.53.0 -3 and -4), so the bundled git version is not the cause.

Expected behavior

Session creation completes: the init fetch finishes and the worktree is created, regardless of whether the clone has core.fsmonitor enabled.

Additional context

Version/onset from ~/.copilot/logs (per-launch version= strings correlated with github_app::git::progress watchdog events):

  • ≤ v1.1.11: 0 idle-timeout events (clean)
  • v1.1.12 (installed Sep 9): 16 events; first fire 2026-09-16T18:16:31Z; idle_timeout_secs changed 300 → 60; hits on the refresh/worktree_sync path
  • v1.1.16: 20 events; first create-path hangs 2026-09-21T14:35Z via create_worktree_workspace / workspace_kickoff_after_init
  • v1.1.22 → v1.1.23 (today): ongoing
    The fetch command string is byte-identical back to July, so the trigger is the surrounding process/env handling + the 300→60s watchdog drop, not the git invocation.

Log signatures: github_app::git::progress ("idle timeout — no stderr activity", idle_timeout_secs=60, received_output=false); create path create_worktree_workspace / workspace_kickoff_after_init; refresh path worktree_sync. The app does not log child-process env, so the GIT_CONFIG_COUNT / core.fsmonitor injection is invisible in logs — please confirm whether the empty override actually reaches the child (the #3980 serialization concern).

Related issues:

Suggested fixes:

  1. Ensure the fsmonitor override reaches the child — pass -c core.fsmonitor=false in the argv, not only via an env override an empty-string-as-missing boundary can drop.
  2. Don't let the spawned fsmonitor daemon inherit the fetch's stderr write-end — redirect the daemon's stderr or close the write-end in the parent after spawn so the progress pipe reaches EOF.
  3. Make the watchdog treat process exit (not only stderr activity) as completion; the 300→60s drop in v1.1.12 just made an existing pipe hazard fail faster.

Workaround: setting core.fsmonitor false (and feature.manyFiles false) on the affected clone stops the daemon from spawning and lets init fetch complete. Per-clone (--local); does not affect other clones of the same repo.

Activity

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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions