hashicorp/nomad · error
failed to get pty: %v
Error message
failed to get pty: %v
What it means
runTTY fails to obtain a pseudo-terminal via the ptyF factory function and wraps the error with this message. The pty allocation happens after the process starts when TTY mode is enabled; without a pty the stdin/stdout bridge cannot be established.
Source
Thrown at drivers/shared/executor/exec_utils.go:67
ptyF, tty, err := e.newTerminal()
if err != nil {
return fmt.Errorf("failed to open a tty: %v", err)
}
defer tty.Close()
if err := e.setTTY(tty); err != nil {
return fmt.Errorf("failed to set command tty: %v", err)
}
if err := e.processStart(); err != nil {
return fmt.Errorf("failed to start command: %v", err)
}
var wg sync.WaitGroup
errCh := make(chan error, 3)
pty, err := ptyF()
if err != nil {
return fmt.Errorf("failed to get pty: %v", err)
}
defer pty.Close()
wg.Add(1)
go handleStdin(e.logger, pty, stream, errCh)
// when tty is on, stdout and stderr point to the same pty so only read once
go handleStdout(e.logger, pty, &wg, stream.Send, errCh)
ps, err := e.processWait()
// force close streams to close out the stream copying goroutines
tty.Close()
// wait until we get all process output
wg.Wait()
// wait to flush out output
stream.Send(cmdExitResult(ps, err))View on GitHub (pinned to 482b49bf1a)
Solutions
- Check host pty exhaustion: cat /proc/sys/kernel/pty/nr vs kernel.pty.max; increase or free ptys
- Ensure /dev/ptmx exists and /dev/pts is mounted in the execution environment
- Inspect the wrapped %v error for the underlying syscall failure
- Review security/seccomp/apparmor policies that may block pty ioctls
- If ptys are unnecessary, run the task with TTY disabled so runNoTTY is used
Example fix
// before (container without pts mounted) // run: mount devpts failed // after (host shell) // sudo mount -t devpts devpts /dev/pts && sysctl -w kernel.pty.max=4096
Defensive patterns
Strategy: try-catch
Validate before calling
func ptysAvailable() bool {
if _, err := os.Stat("/dev/ptmx"); err != nil { return false }
b, err := os.ReadFile("/proc/sys/kernel/pty/nr")
if err != nil { return false }
max, err := os.ReadFile("/proc/sys/kernel/pty/max")
if err != nil { return false }
return strings.TrimSpace(string(b)) != strings.TrimSpace(string(max))
} Try / catch
if err := startTaskWithTTY(); err != nil {
if strings.Contains(err.Error(), "failed to get pty") {
// fall back to non-tty launch or reschedule on another node
return startTaskWithoutTTY()
}
return err
} Prevention
- Mount devpts in containers that run executors
- Raise kernel.pty.max on exec-heavy nodes
- Avoid requesting tty for non-interactive tasks
- Verify seccomp profiles allow pty ioctls
When it happens
Trigger: run() with command.Tty=true reaches `pty, err := ptyF()` and pty allocation fails — typically openpty/ptmx open failures.
Common situations: Host out of ptys (kernel.pty.max exhausted), running inside a container/namespace without /dev/ptmx or restricted device cgroup, missing pty kernel module, seccomp/apparmor blocking TIOCGPTN/ioctl calls.
Related errors
- failed to open a tty: %v
- failed to start command: %v
- failed to set command io: %v
- failed to resize tty: %v
- attempted to resize a non-tty session
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/f1ddee8b55f092af.
Report an issue: GitHub.