[shell] stdin_write blocks the main thread while the child isn't reading stdin

Open
#3,748 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 3 days

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
rust
Domain
backend, cli

Research direction

Start by reading the stdin_write command and the shell child management code that protects shell.children with a lock; the issue does not name file paths or tests. Compare the async kill change in issue #3351 and trace how writes from JavaScript preserve order. Done means large writes no longer block the main thread, while child cleanup and other commands can proceed and writes remain ordered; the issue leaves the design open.

Written by the indexing model from the issue text.

Description

plugin: shell type: bug
Describe the bug

stdin_write is a sync command, so it runs on the main thread, and it does a blocking write_all into the child's stdin pipe. If the data is bigger than the pipe buffer and the child isn't reading its stdin at that moment, the main thread waits until the child reads. The whole window freezes for that time, and if the child never reads stdin it stays frozen.

It also holds shell.children.lock() during the write, so from reading the code every other shell command (spawn, kill, writes to other children) and the Terminated cleanup wait on that lock too. I only measured the main thread part.

#3351 made kill async for the same main thread reason, stdin_write is still sync.

Reproduction

Spawn sh -c 'sleep 6; cat >/dev/null' from JS, call child.write() (plugin:shell|stdin_write) with 1 MiB, then 100 ms later call any other sync command and time it.

macOS 26.5.1, Tauri 2.12.5, tauri-plugin-shell 2.6.0:

32 KiB write: the other command answers in 1 ms

1 MiB write, child reads after 6 s: the other command answers after 5918 ms and 5916 ms (2 runs)

1 MiB write, child reads after 20 s: 19918 ms

A stack sample of the 20 s run, taken while it was stuck, has the main thread in tauri_plugin_shell::commands::stdin_write > std::io::Write::write_all > write in 2605 of 2605 samples.

I can put the probe app in a repo if that helps.

Expected behavior

Writing to a child's stdin shouldn't block the main thread, at least not for longer than it takes to copy the data.

Full tauri info output
[✘] Environment
    - OS: Mac OS 26.5.1 arm64 (X64)
    ✔ Xcode Command Line Tools: installed
    ✘ Xcode: not installed!
    ✔ rustc: 1.95.0 (59807616e 2026-04-14)
    ✔ cargo: 1.95.0 (f2d3ce0bd 2026-03-21)
    ✔ rustup: 1.29.1 (d95a37b6a 2026-08-13)
    ✔ Rust toolchain: stable-aarch64-apple-darwin (default)
    - node: 26.8.1
    - pnpm: 12.11.2
    - yarn: 1.22.22
    - npm: 11.19.0
    - bun: 1.4.2
    - deno: deno 2.9.7

[-] Packages
    - tauri 🦀: 2.12.5
    - tauri-build 🦀: 2.7.4
    - wry 🦀: 0.57.1
    - tao 🦀: 0.37.2

[-] Plugins
    - tauri-plugin-shell 🦀: 2.6.0

[-] App
    - build-type: build
    - CSP: unset
    - frontendDist: dist
Additional context

I'd like to send a fix but the shape needs a decision, which is why this is an issue first. Just making the command async moves the wait off the main thread, but the write would still hold the children lock, so a kill meant to get out of the stuck write would wait behind it. And writes from JS would need to keep their order, which they get for free today because they all run on the main thread.

One way: make it async, take what's needed to write out of children under the lock (or give each child its own writer task with a queue, so order is kept), and do the blocking write in spawn_blocking. Happy to do whichever you prefer.

Dominant language
Rust
Stars
1.8k
Forks
637
Avg merge
5d 3h
Merged PRs (30d)
36

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from tauri-apps/plugins-workspace

All issues in tauri-apps/plugins-workspace

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.