{"record":{"id":"f1ddee8b55f092af","repo":"hashicorp/nomad","slug":"failed-to-get-pty-v","errorCode":null,"errorMessage":"failed to get pty: %v","messagePattern":"failed to get pty: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/shared/executor/exec_utils.go","lineNumber":67,"sourceCode":"\tptyF, tty, err := e.newTerminal()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open a tty: %v\", err)\n\t}\n\tdefer tty.Close()\n\n\tif err := e.setTTY(tty); err != nil {\n\t\treturn fmt.Errorf(\"failed to set command tty: %v\", err)\n\t}\n\tif err := e.processStart(); err != nil {\n\t\treturn fmt.Errorf(\"failed to start command: %v\", err)\n\t}\n\n\tvar wg sync.WaitGroup\n\terrCh := make(chan error, 3)\n\n\tpty, err := ptyF()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get pty: %v\", err)\n\t}\n\n\tdefer pty.Close()\n\twg.Add(1)\n\tgo handleStdin(e.logger, pty, stream, errCh)\n\t// when tty is on, stdout and stderr point to the same pty so only read once\n\tgo handleStdout(e.logger, pty, &wg, stream.Send, errCh)\n\n\tps, err := e.processWait()\n\n\t// force close streams to close out the stream copying goroutines\n\ttty.Close()\n\n\t// wait until we get all process output\n\twg.Wait()\n\n\t// wait to flush out output\n\tstream.Send(cmdExitResult(ps, err))","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/shared/executor/exec_utils.go#L49-L85","documentation":"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.","triggerScenarios":"run() with command.Tty=true reaches `pty, err := ptyF()` and pty allocation fails — typically openpty/ptmx open failures.","commonSituations":"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.","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"],"exampleFix":"// before (container without pts mounted)\n// run: mount devpts failed\n// after (host shell)\n// sudo mount -t devpts devpts /dev/pts && sysctl -w kernel.pty.max=4096","handlingStrategy":"try-catch","validationCode":"func ptysAvailable() bool {\n  if _, err := os.Stat(\"/dev/ptmx\"); err != nil { return false }\n  b, err := os.ReadFile(\"/proc/sys/kernel/pty/nr\")\n  if err != nil { return false }\n  max, err := os.ReadFile(\"/proc/sys/kernel/pty/max\")\n  if err != nil { return false }\n  return strings.TrimSpace(string(b)) != strings.TrimSpace(string(max))\n}","typeGuard":null,"tryCatchPattern":"if err := startTaskWithTTY(); err != nil {\n  if strings.Contains(err.Error(), \"failed to get pty\") {\n    // fall back to non-tty launch or reschedule on another node\n    return startTaskWithoutTTY()\n  }\n  return err\n}","preventionTips":["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"],"tags":["pty","tty","process","nomad-executor"],"backgroundTag":"pty-allocation-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}