Hmbown/CodeWhale · warning
PTY job is no longer running
Error message
PTY job is no longer running
What it means
After resolving the job, resize_pty polls it and requires ShellStatus::Running before touching the PTY master; a finished (exited, failed, killed, or evicted-pending) job fails with 'PTY job is no longer running'. Resizing a dead pseudo-terminal would either error in portability internals or silently do nothing, so the manager rejects it with this explicit state error.
Solutions
- Check job status (via get_output/poll_status or the job list) and skip the resize when it is not Running.
- Drop queued resize events when the job reaches a terminal status.
- If the job should still be alive, inspect its exit code/stderr to see why it exited before attempting further interaction.
- Re-run the command with a fresh task_id if an interactive PTY session is still needed.
Example fix
// before
manager.resize_pty(task_id, size)?;
// after
match manager.poll_status(task_id) {
Ok(s) if s == ShellStatus::Running => manager.resize_pty(task_id, size)?,
Ok(s) => eprintln!("job {task_id} is {s:?}; skipping resize"),
Err(_) => eprintln!("job {task_id} untracked; skipping resize"),
} Defensive patterns
Strategy: validation
Validate before calling
// Rust: gate the resize on live Running status
let status = manager.poll_status(task_id)?; // errors if untracked
if status == ShellStatus::Running {
manager.resize_pty(task_id, size)?;
} else {
eprintln!("job {task_id} is {status:?}; skipping PTY resize");
} Type guard
fn is_running(status: &ShellStatus) -> bool { *status == ShellStatus::Running } Try / catch
match manager.resize_pty(task_id, size) {
Ok(()) => (),
Err(e) if e.to_string().contains("no longer running") => {
// read final output/exit code instead of resizing
let final_out = manager.get_output(task_id, false, 0)?;
}
Err(e) => return Err(e),
} Prevention
- Subscribe to job completion events and cancel pending resize requests on terminal status
- Check poll_status/get_output before resizing, especially after long waits
- Never resize a PTY job after observing a non-Running status — the check is not recoverable
- Treat this as a benign race in UI code: log and skip rather than failing the whole interaction
When it happens
Trigger: Calling resize_pty on a tracked job whose process has already exited — e.g. the job finished between spawn and the resize call, was killed, or the resize event arrives after process exit.
Common situations: Terminal SIGWINCH-style resize delivered just after a long-running command finished; UI resizing a panel bound to a completed PTY job; race between job exit notification and a queued resize request.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- A cancelled Operation cannot be edited.
- DSH is already connected; use
- DSH is not connected; nothing to
- DSH is not connected; run
- element does not belong to the bound application —…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/7d223f47f2540c2a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/shell.rs:2918
shell.write_stdin_bytes(input, close)?;
Ok(())
}
/// Historical evicted records have no terminal-size evidence.
pub fn job_terminal_size(&self, task_id: &str) -> Option<PtyDimensions> {
self.processes
.get(task_id)
.and_then(|shell| shell.terminal_size)
}
pub fn resize_pty(&mut self, task_id: &str, size: PtyDimensions) -> Result<()> {
let size = size.validate()?;
let shell = self
.processes
.get_mut(task_id)
.ok_or_else(|| anyhow!("Job {task_id} not found"))?;
shell.poll();
anyhow::ensure!(
shell.status == ShellStatus::Running,
"PTY job is no longer running"
);
#[cfg(not(target_env = "ohos"))]
{
let master = shell.pty_master.as_ref().context("Job is not a PTY")?;
master
.resize(PtySize {
rows: size.rows,
cols: size.cols,
pixel_width: 0,
pixel_height: 0,
})
.context("Failed to resize PTY")?;
shell.terminal_size = Some(size);
Ok(())
}
#[cfg(target_env = "ohos")]View on GitHub (pinned to 73e0f67d83)