Skip to content

Fix file descriptor leaks in async workers#856

Open
SaeGon-Heo wants to merge 1 commit into
marlonrichert:mainfrom
SaeGon-Heo:main
Open

Fix file descriptor leaks in async workers#856
SaeGon-Heo wants to merge 1 commit into
marlonrichert:mainfrom
SaeGon-Heo:main

Conversation

@SaeGon-Heo

Copy link
Copy Markdown

Note: The description for this PR was drafted with the help of Gemini 3.1 Pro.

Before submitting your Pull Request (PR), please check the following:

  • There is no other PR (open or closed) similar to yours. If there is, please first discuss over there.
  • Your new code in each file follows the same style as the existing code in that file.
  • Each commit messages follows the Seven Rules of a Great Commit Message.
  • Each commit message includes Fixes #<bug> or Resolves #<issue> in its body (not subject, that is, the first line) for each issue it resolves (if any).
  • You have squashed any redundant or insignificant commits.

The Problem
After extended use of the terminal, users experience recurring crashes with the following error messages, eventually completely breaking autocompletion:

.autocomplete:async:wait:sysopen:2: can't open file /dev/fd/-1: no such file or directory
.autocomplete:async:wait:17: write error: bad file descriptor

This occurs because the plugin leaks file descriptors on every keystroke. Once the OS open-file limit is reached (commonly 256), Zsh fails to allocate new pipes for process substitution <(...).

Root Causes
Upon investigating Functions/Init/.autocomplete__async, two bugs prevent FDs from closing:

  1. Typo in .autocomplete:async:clear: The if condition checks for _autocomplete__async_fd (double underscore), while the actual file descriptor is stored in _autocomplete_async_fd (single underscore). The cleanup block is bypassed entirely when exiting ZLE.
  2. Flawed FD check ([[ -t $fd ]]): In multiple functions, the code uses [[ -t $fd ]] before closing the descriptor via exec {fd}<&-. The -t flag checks if an FD is connected to a terminal (TTY). Because the async workers use pipes, they are never connected to a terminal, so this evaluates to false 100% of the time, leaking the FD.

Proposed Changes

  • Functions/Init/.autocomplete__async:
    • Fixed the variable name typo in .autocomplete:async:clear.
    • Removed the [[ -t $fd ]] checks in .autocomplete:async:clear, .autocomplete:async:wait:fd-widget, and .autocomplete:async:complete:fd-widget.
    • Replaced them with { : <&$fd } 2>/dev/null && exec {fd}<&-. This safely peeks to see if the file descriptor is open before closing it. Importantly, it avoids using a bare exec 2>/dev/null, which would unintentionally redirect the global shell stderr and break the output of background commands like git clone.

@SaeGon-Heo SaeGon-Heo force-pushed the main branch 2 times, most recently from 632bf77 to d6ce109 Compare April 10, 2026 06:21
Fixes marlonrichert#853

1. Correct a variable name typo in the clear function
(_autocomplete__async_fd -> _autocomplete_async_fd).
2. Replace faulty terminal checks (-t) that prevented
background pipes from closing. Use a safe redirection check
({ : <&$fd } 2>/dev/null) to verify pipe status before closing.
3. This resolves FD exhaustion (/dev/fd/-1) without redirecting
global stderr, which previously silenced commands like git clone.
orland0m pushed a commit to orland0m/zsh-autocomplete that referenced this pull request May 4, 2026
Replace -t (is-a-terminal) fd checks with actual read attempts to
properly detect open file descriptors. The -t test only checks if an
fd is a terminal, which is incorrect for pipes used by async workers,
causing fd leaks.

Also fixes variable name from _autocomplete__async_fd (double
underscore) to _autocomplete_async_fd (single underscore) in the
async:clear function.

Ref: marlonrichert#856
Fixes: marlonrichert#853
@Chromiell

Copy link
Copy Markdown

I tested your branch and it does seem to fix the issue on my Debian machines, oddly enough this bug does not show up in my Ubuntu 24.04 environment. I'll switch to your branch for now until the fix will get merged, hopefully soon, since the bug is incredibly annoying. Thank you very much for your contribution!

@deathbeam

Copy link
Copy Markdown
Contributor

This fixed my issue as well (still had the issue with just the typo fix, the rest was needed too).

@pablon

pablon commented May 30, 2026

Copy link
Copy Markdown

@marlonrichert we've validated the patch proposed by @SaeGon-Heo fixes all leak issues. Can you review/merge this PR?

zsh 5.9 (x86_64-apple-darwin23.0)

@SaeGon-Heo

SaeGon-Heo commented May 30, 2026

Copy link
Copy Markdown
Author

@marlonrichert
sorry for annoyance. I made this pr but, I found this pr is mishandling typo in autocomplete__async although other one's use double underscore pattern in same dir. And Im afread to add commit because of PR template rule You have [squashed](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#_squashing) any redundant or insignificant commits.
Its been 1 month, may you check this PR when you have a time?

@MateuszWojciechowskiDash0

Copy link
Copy Markdown

Please treat this as a priority, this is killing me I had to turn off the plugin for the time being

@kushvinth

Copy link
Copy Markdown
.autocomplete:async:wait:17: write error: bad file descriptor

Poor Stuff

@MrKalach

MrKalach commented Jul 2, 2026

Copy link
Copy Markdown

Please treat this as a priority, this is killing me I had to turn off the plugin for the time being

same here

@pablon

pablon commented Jul 3, 2026

Copy link
Copy Markdown

@marlonrichert sorry for annoyance. I made this pr but, I found this pr is mishandling typo in autocomplete__async although other one's use double underscore pattern in same dir. And Im afread to add commit because of PR template rule You have [squashed](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#_squashing) any redundant or insignificant commits. Its been 1 month, may you check this PR when you have a time?

@SaeGon-Heo This patch really works. Have you tried creating a brand new PR with clean commits/pushes so it can go through?

@SaeGon-Heo

Copy link
Copy Markdown
Author

@marlonrichert
I have opened a new PR (#868) with the correct naming conventions.
please check new one :)
@pablon and others
The maintainer's profile shows no activity since May 5th, so he seems to be busy lately and this new PR might not be merged immediately.
In the meantime, you can temporarily download the patched .autocomplete__async file from this link and overwrite it in your {plugin home}/Functions/Init/ directory.
This approach would be better because you can cleanly run git pull without any conflicts once the official PR is merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants