Skip to content

Conversation

@RemiKalbe
Copy link
Contributor

@RemiKalbe RemiKalbe commented Oct 20, 2025

Summary

Fixes #36754

This PR fixes an issue where LSPs fail to spawn after the crash handler is initialized.

Problem

After PR #35263 added minidump crash reporting, some users experienced LSP spawn failures. The issue manifests as:

  • LSPs fail to spawn with no clear error messages
  • The problem only occurs after crash handler initialization
  • LSPs work when a debugger is attached, revealing a timing issue

Root Cause

The crash handler installs Mach exception ports for minidump generation. Due to a timing issue, child processes inherit these exception ports before they're fully stabilized, which can block child process spawning.

Solution

Reset exception ports in child processes using the pre_exec() hook, which runs after fork() but before exec(). This prevents children from inheriting the parent's crash handler exception ports.

Implementation

  • Adds macOS-specific implementation of new_smol_command() that resets exception ports before exec
  • Calls task_set_exception_ports to reset all exception ports to MACH_PORT_NULL
  • Graceful error handling: logs warnings but doesn't fail process spawning if port reset fails

Release Notes:

  • Fixed LSPs failing to spawn after crash handler initialization on some macOS systems
Fixes zed-industries#36754

LSPs fail to spawn after the crash handler is initialized. This is caused
by a timing issue where child processes inherit the parent's crash handler
exception ports before they're fully stabilized, which can block process
spawning.

This fix resets exception ports in child processes before exec using the
pre_exec() hook, preventing them from inheriting the parent's crash handler
exception ports.

Changes:
- Reset exception ports to system defaults in child processes
- Use pre_exec() to run in child after fork but before exec
- Graceful error handling with warning logs
@cla-bot
Copy link

cla-bot bot commented Oct 20, 2025

We require contributors to sign our Contributor License Agreement, and we don't have @RemiKalbe on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@RemiKalbe
Copy link
Contributor Author

@cla-bot check

@cla-bot
Copy link

cla-bot bot commented Oct 20, 2025

We require contributors to sign our Contributor License Agreement, and we don't have @RemiKalbe on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@cla-bot
Copy link

cla-bot bot commented Oct 20, 2025

The cla-bot has been summoned, and re-checked this pull request!

@RemiKalbe
Copy link
Contributor Author

@cla-bot check

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Oct 20, 2025
@cla-bot
Copy link

cla-bot bot commented Oct 20, 2025

The cla-bot has been summoned, and re-checked this pull request!

Copy link
Member

@Veykril Veykril left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, this does sound reasonable, but gonna ask for a second opinion from @P1n3appl3

@Veykril Veykril requested a review from P1n3appl3 October 31, 2025 08:00
Copy link
Contributor

@P1n3appl3 P1n3appl3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just double checked that the crash reporting signal handling still works correctly on mac with this change. I wish it were easier to test the case you're talking about with the language servers, but if it fixes it for you and doesn't regress other stuff I'm happy to merge. Sorry it took so long, this got lost in the sea of PRs in my inbox 😅 .

@RemiKalbe
Copy link
Contributor Author

You're fine! Yeah this bug is weird but that does fix it, I've been using this build ever since and I've not encountered any issues 😄

@P1n3appl3 P1n3appl3 enabled auto-merge (squash) November 5, 2025 22:03
@P1n3appl3 P1n3appl3 merged commit 8315fde into zed-industries:main Nov 5, 2025
24 checks passed
maxbrunsfeld pushed a commit that referenced this pull request Nov 6, 2025
)

## Summary

Fixes #36754

This PR fixes an issue where LSPs fail to spawn after the crash handler
is initialized.

## Problem

After PR #35263 added minidump crash reporting, some users experienced
LSP spawn failures. The issue manifests as:
- LSPs fail to spawn with no clear error messages
- The problem only occurs after crash handler initialization
- LSPs work when a debugger is attached, revealing a timing issue

### Root Cause

The crash handler installs Mach exception ports for minidump generation.
Due to a timing issue, child processes inherit these exception ports
before they're fully stabilized, which can block child process spawning.

## Solution

Reset exception ports in child processes using the `pre_exec()` hook,
which runs after `fork()` but before `exec()`. This prevents children
from inheriting the parent's crash handler exception ports.

### Implementation

- Adds macOS-specific implementation of `new_smol_command()` that resets
exception ports before exec
- Calls `task_set_exception_ports` to reset all exception ports to
`MACH_PORT_NULL`
- Graceful error handling: logs warnings but doesn't fail process
spawning if port reset fails

Release Notes:

- Fixed LSPs failing to spawn on some macOS systems

---------

Co-authored-by: Julia Ryan <juliaryan3.14@gmail.com>
maxbrunsfeld pushed a commit that referenced this pull request Nov 6, 2025
)

## Summary

Fixes #36754

This PR fixes an issue where LSPs fail to spawn after the crash handler
is initialized.

## Problem

After PR #35263 added minidump crash reporting, some users experienced
LSP spawn failures. The issue manifests as:
- LSPs fail to spawn with no clear error messages
- The problem only occurs after crash handler initialization
- LSPs work when a debugger is attached, revealing a timing issue

### Root Cause

The crash handler installs Mach exception ports for minidump generation.
Due to a timing issue, child processes inherit these exception ports
before they're fully stabilized, which can block child process spawning.

## Solution

Reset exception ports in child processes using the `pre_exec()` hook,
which runs after `fork()` but before `exec()`. This prevents children
from inheriting the parent's crash handler exception ports.

### Implementation

- Adds macOS-specific implementation of `new_smol_command()` that resets
exception ports before exec
- Calls `task_set_exception_ports` to reset all exception ports to
`MACH_PORT_NULL`
- Graceful error handling: logs warnings but doesn't fail process
spawning if port reset fails

Release Notes:

- Fixed LSPs failing to spawn on some macOS systems

---------

Co-authored-by: Julia Ryan <juliaryan3.14@gmail.com>
tomatitito pushed a commit to tomatitito/zed that referenced this pull request Nov 7, 2025
…-industries#40716)

## Summary

Fixes zed-industries#36754

This PR fixes an issue where LSPs fail to spawn after the crash handler
is initialized.

## Problem

After PR zed-industries#35263 added minidump crash reporting, some users experienced
LSP spawn failures. The issue manifests as:
- LSPs fail to spawn with no clear error messages
- The problem only occurs after crash handler initialization
- LSPs work when a debugger is attached, revealing a timing issue

### Root Cause

The crash handler installs Mach exception ports for minidump generation.
Due to a timing issue, child processes inherit these exception ports
before they're fully stabilized, which can block child process spawning.

## Solution

Reset exception ports in child processes using the `pre_exec()` hook,
which runs after `fork()` but before `exec()`. This prevents children
from inheriting the parent's crash handler exception ports.

### Implementation

- Adds macOS-specific implementation of `new_smol_command()` that resets
exception ports before exec
- Calls `task_set_exception_ports` to reset all exception ports to
`MACH_PORT_NULL`
- Graceful error handling: logs warnings but doesn't fail process
spawning if port reset fails

Release Notes:

- Fixed LSPs failing to spawn on some macOS systems

---------

Co-authored-by: Julia Ryan <juliaryan3.14@gmail.com>
11happy pushed a commit to 11happy/zed that referenced this pull request Dec 1, 2025
…-industries#40716)

## Summary

Fixes zed-industries#36754

This PR fixes an issue where LSPs fail to spawn after the crash handler
is initialized.

## Problem

After PR zed-industries#35263 added minidump crash reporting, some users experienced
LSP spawn failures. The issue manifests as:
- LSPs fail to spawn with no clear error messages
- The problem only occurs after crash handler initialization
- LSPs work when a debugger is attached, revealing a timing issue

### Root Cause

The crash handler installs Mach exception ports for minidump generation.
Due to a timing issue, child processes inherit these exception ports
before they're fully stabilized, which can block child process spawning.

## Solution

Reset exception ports in child processes using the `pre_exec()` hook,
which runs after `fork()` but before `exec()`. This prevents children
from inheriting the parent's crash handler exception ports.

### Implementation

- Adds macOS-specific implementation of `new_smol_command()` that resets
exception ports before exec
- Calls `task_set_exception_ports` to reset all exception ports to
`MACH_PORT_NULL`
- Graceful error handling: logs warnings but doesn't fail process
spawning if port reset fails

Release Notes:

- Fixed LSPs failing to spawn on some macOS systems

---------

Co-authored-by: Julia Ryan <juliaryan3.14@gmail.com>
RemiKalbe added a commit to RemiKalbe/zed that referenced this pull request Dec 5, 2025
The original fix in zed-industries#40716 only applied to processes spawned via
`new_smol_command()`, but shell environment capture uses a different
code path: `new_std_command()` → `set_pre_exec_to_start_new_session()`
→ convert to smol::process::Command.

This caused an issue where:
1. Zed spawns a login shell to capture environment variables
2. The shell sources user config (e.g., .zshrc with oh-my-zsh plugins)
3. Plugins may spawn background processes (e.g., `poetry completions zsh &|`)
4. These processes inherit the crash handler's exception ports
5. The inherited exception ports can cause the processes to hang
6. The hanging process keeps the pipe to Zed open
7. Zed's `read_to_end()` blocks waiting for the pipe to close
8. This prevents Zed from spawning any more processes (including LSPs)

Fix by also calling `reset_exception_ports()` in
`set_pre_exec_to_start_new_session()`, which is used by shell
environment capture, terminal spawning, and DAP transport.

Fixes zed-industries#36754
RemiKalbe added a commit to RemiKalbe/zed that referenced this pull request Dec 5, 2025
The original fix in zed-industries#40716 only applied to processes spawned via
`new_smol_command()`, but shell environment capture uses a different
code path: `new_std_command()` → `set_pre_exec_to_start_new_session()`
→ convert to smol::process::Command.

This caused an issue where:
1. Zed spawns a login shell to capture environment variables
2. The shell sources user config (e.g., .zshrc with oh-my-zsh plugins)
3. Plugins may spawn background processes (e.g., `poetry completions zsh &|`)
4. These processes inherit the crash handler's exception ports
5. The inherited exception ports can cause the processes to hang
6. The hanging process keeps the pipe to Zed open
7. Zed's `read_to_end()` blocks waiting for the pipe to close
8. This prevents Zed from spawning any more processes (including LSPs)

Fix by also calling `reset_exception_ports()` in
`set_pre_exec_to_start_new_session()`, which is used by shell
environment capture, terminal spawning, and DAP transport.

Fixes zed-industries#36754
Veykril pushed a commit that referenced this pull request Dec 8, 2025
## Summary

Follow-up to #40716. This applies the same `reset_exception_ports()` fix
to `set_pre_exec_to_start_new_session()`, which is used by shell
environment capture, terminal spawning, and DAP transport.

### Root Cause

After more debugging, I finally figured out what was causing the issue
on my machine. Here's what was happening:

1. Zed spawns a login shell (zsh) to capture environment variables
2. A pipe is created: reader in Zed, writer mapped to fd 0 in zsh
3. zsh sources `.zshrc` → loads oh-my-zsh → runs poetry plugin
4. Poetry plugin runs `poetry completions zsh &|` in background
5. Poetry inherits fd 0 (the pipe's write end) from zsh
6. zsh finishes `zed --printenv` and exits
7. Poetry still holds fd 0 open
8. Zed's `reader.read_to_end()` blocks waiting for all writers to close
9. Poetry hangs (likely due to inherited crash handler exception ports
interfering with its normal operation)
10. Pipe stays open → Zed stuck → no more processes spawn (including
LSPs)

I confirmed this by killing the hanging `poetry` process, which
immediately unblocked Zed and allowed LSPs to start. However, this
workaround was needed every time I started Zed.

While poetry was the culprit in my case, this can affect any shell
configuration that spawns background processes during initialization
(oh-my-zsh plugins, direnv, asdf, nvm, etc.).

Fixes #36754

## Test plan

- [x] Build with `ZED_GENERATE_MINIDUMPS=true` to force crash handler
initialization
- [x] Verify crash handler logs appear ("spawning crash handler
process", "crash handler registered")
- [x] Confirm LSPs start correctly with shell plugins that spawn
background processes

Release Notes:

- Fixed an issue on macOS where LSPs could fail to start when shell
plugins spawn background processes during environment capture.
CherryWorm pushed a commit to CherryWorm/zed that referenced this pull request Dec 16, 2025
…ies#44193)

## Summary

Follow-up to zed-industries#40716. This applies the same `reset_exception_ports()` fix
to `set_pre_exec_to_start_new_session()`, which is used by shell
environment capture, terminal spawning, and DAP transport.

### Root Cause

After more debugging, I finally figured out what was causing the issue
on my machine. Here's what was happening:

1. Zed spawns a login shell (zsh) to capture environment variables
2. A pipe is created: reader in Zed, writer mapped to fd 0 in zsh
3. zsh sources `.zshrc` → loads oh-my-zsh → runs poetry plugin
4. Poetry plugin runs `poetry completions zsh &|` in background
5. Poetry inherits fd 0 (the pipe's write end) from zsh
6. zsh finishes `zed --printenv` and exits
7. Poetry still holds fd 0 open
8. Zed's `reader.read_to_end()` blocks waiting for all writers to close
9. Poetry hangs (likely due to inherited crash handler exception ports
interfering with its normal operation)
10. Pipe stays open → Zed stuck → no more processes spawn (including
LSPs)

I confirmed this by killing the hanging `poetry` process, which
immediately unblocked Zed and allowed LSPs to start. However, this
workaround was needed every time I started Zed.

While poetry was the culprit in my case, this can affect any shell
configuration that spawns background processes during initialization
(oh-my-zsh plugins, direnv, asdf, nvm, etc.).

Fixes zed-industries#36754

## Test plan

- [x] Build with `ZED_GENERATE_MINIDUMPS=true` to force crash handler
initialization
- [x] Verify crash handler logs appear ("spawning crash handler
process", "crash handler registered")
- [x] Confirm LSPs start correctly with shell plugins that spawn
background processes

Release Notes:

- Fixed an issue on macOS where LSPs could fail to start when shell
plugins spawn background processes during environment capture.
someone13574 pushed a commit to someone13574/zed that referenced this pull request Dec 16, 2025
…ies#44193)

## Summary

Follow-up to zed-industries#40716. This applies the same `reset_exception_ports()` fix
to `set_pre_exec_to_start_new_session()`, which is used by shell
environment capture, terminal spawning, and DAP transport.

### Root Cause

After more debugging, I finally figured out what was causing the issue
on my machine. Here's what was happening:

1. Zed spawns a login shell (zsh) to capture environment variables
2. A pipe is created: reader in Zed, writer mapped to fd 0 in zsh
3. zsh sources `.zshrc` → loads oh-my-zsh → runs poetry plugin
4. Poetry plugin runs `poetry completions zsh &|` in background
5. Poetry inherits fd 0 (the pipe's write end) from zsh
6. zsh finishes `zed --printenv` and exits
7. Poetry still holds fd 0 open
8. Zed's `reader.read_to_end()` blocks waiting for all writers to close
9. Poetry hangs (likely due to inherited crash handler exception ports
interfering with its normal operation)
10. Pipe stays open → Zed stuck → no more processes spawn (including
LSPs)

I confirmed this by killing the hanging `poetry` process, which
immediately unblocked Zed and allowed LSPs to start. However, this
workaround was needed every time I started Zed.

While poetry was the culprit in my case, this can affect any shell
configuration that spawns background processes during initialization
(oh-my-zsh plugins, direnv, asdf, nvm, etc.).

Fixes zed-industries#36754

## Test plan

- [x] Build with `ZED_GENERATE_MINIDUMPS=true` to force crash handler
initialization
- [x] Verify crash handler logs appear ("spawning crash handler
process", "crash handler registered")
- [x] Confirm LSPs start correctly with shell plugins that spawn
background processes

Release Notes:

- Fixed an issue on macOS where LSPs could fail to start when shell
plugins spawn background processes during environment capture.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

3 participants