slint-ui/slint · error
Child has no stdin
Error message
Child has no stdin
What it means
Same family as [212] but for stdin: the preview child is spawned with `stdin(Stdio::piped())` and `child.stdin.take()` must yield the pipe. None means the pipe was not configured or already taken. This is an internal invariant; stock builds always pipe stdin.
Solutions
- Ensure `.stdin(std::process::Stdio::piped())` is present in the spawn options
- Take stdin only once per spawned child; spawn a fresh child for each preview session
- Rebuild slint-lsp from a clean checkout
- File a bug if reproducible on an unmodified build
Example fix
// before: reusing stale child
let child = &mut self.cached_child;
let mut to_child = child.stdin.take().expect("Child has no stdin");
// after: spawn fresh per session
let mut child = command.spawn()?;
let mut to_child = child.stdin.take().expect("Child has no stdin"); Defensive patterns
Strategy: validation
Validate before calling
let Some(stdin) = child.stdin.take() else { return Err("preview child stdin missing"); }; Type guard
fn has_stdin(child: &std::process::Child) -> bool { child.stdin.is_some() } Try / catch
// treat a missing pipe as a restartable failure
if child.stdin.is_none() { respawn_preview()?; } Prevention
- Keep `.stdin(std::process::Stdio::piped())` in spawn options
- Take stdin only once per child
- Restart logic should spawn a new process, not reuse an old Child
When it happens
Trigger: `start_preview` (called from `send`) after the child's stdin handle was already taken, or if the spawn's `.stdin(Stdio::piped())` was dropped/modified.
Common situations: Patched builds changing spawn options; calling start_preview twice on the same Child struct; a bug in preview restart logic reusing handles.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Child has no stdout
- Could not find executable name of the slint-lsp
- Identifier is in unknown document
- URL conversion can not fail here
- Callbacks were set up earlier
AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16).
Data as JSON: /api/errors/0d2acb72ddf474f6.
Report an issue: GitHub.
Appendix: source
Thrown at internal/editor-preview/child_process.rs:55
fn preview_is_running(&self) -> bool {
self.inner.borrow().as_ref().map(|i| !i.communication_handle.is_finished()).unwrap_or(false)
}
fn start_preview(&self) -> crate::Result<()> {
if let Some(inner) = self.inner.borrow_mut().take() {
inner.communication_handle.abort();
}
let mut child = tokio::process::Command::new(&self.executable)
.args(&self.arguments)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn()?;
tracing::debug!("Preview process spawned (PID {:?})", child.id());
let from_child = child.stdout.take().expect("Child has no stdout");
let mut to_child = child.stdin.take().expect("Child has no stdin");
let channel = self.preview_to_lsp_channel.clone();
let communication_handle = tokio::spawn(async move {
let _exited_guard = scopeguard::guard(channel.clone(), |channel| {
channel.send(PreviewToLspMessage::Exited).ok();
});
let reader = tokio::io::BufReader::new(from_child);
let mut lines = reader.lines();
while let Some(line) = lines.next_line().await.map_err(|e| e.to_string())? {
if let Ok(message) = serde_json::from_str(&line) {
channel.send(message).map_err(|e| e.to_string())?;
}
}
let exit_status = child.wait().await.map_err(|e| e.to_string());
if exit_status.map(|exit_status| !exit_status.success()).unwrap_or(true) {View on GitHub (pinned to bb937076de)