hashicorp/nomad · error

failed to create terminal: %v

Error message

failed to create terminal: %v

What it means

newTerminalSocket creates a socket pair via lutils.NewSockPair to serve as the task's terminal (pty parent/tty child). If creating the socket pair fails (e.g. the unix socket temp path is unusable), the error is wrapped as "failed to create terminal". Without the terminal pair the container cannot be launched with an attached TTY.

Source

Thrown at drivers/shared/executor/executor_linux_cgo.go:579

			}
		}
		var exitCode int
		if status, ok := ps.Sys().(syscall.WaitStatus); ok {
			exitCode = status.ExitStatus()
		}
		return buf.Bytes(), exitCode, nil

	case <-time.After(time.Until(deadline)):
		process.Signal(os.Kill)
		return nil, 0, context.DeadlineExceeded
	}

}

func (l *LibcontainerExecutor) newTerminalSocket() (pty func() (*os.File, error), tty *os.File, err error) {
	parent, child, err := lutils.NewSockPair("socket")
	if err != nil {
		return nil, nil, fmt.Errorf("failed to create terminal: %v", err)
	}

	return func() (*os.File, error) { return lutils.RecvFile(parent) }, child, err

}

func (l *LibcontainerExecutor) ExecStreaming(ctx context.Context, cmd []string, tty bool,
	stream drivers.ExecTaskStream) error {

	// the task process will be started by the container
	process := &libcontainer.Process{
		Args: cmd,
		Env:  l.userProc.Env,
		UID:  l.userProc.UID,
		Init: false,
		Cwd:  l.command.WorkDir,
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check file descriptor usage (ulimit -n, lsof on nomad) and raise limits if EMFILE
  2. Ensure TMPDIR (default /tmp) is writable and has space for unix sockets
  3. Check LSM policies (SELinux/AppArmor) permitting unix socket creation by the Nomad process
  4. Upgrade/restart Nomad; some terminal socket cleanup bugs were fixed in later releases
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check temp dir writability and fd headroom
if f, err := os.CreateTemp(os.TempDir(), "sock-test"); err != nil {
    return fmt.Errorf("TMPDIR unusable for sockets: %w", err)
} else { f.Close(); os.Remove(f.Name()) }
if n, _ := countOpenFDs(); n > fdLimit-64 { return fmt.Errorf("fd exhaustion risk") }

Try / catch

if _, err := executor.Launch(cmd); err != nil && strings.Contains(err.Error(), "failed to create terminal") {
    log.Printf("terminal socketpair failed: %v — check TMPDIR/fd limits", err)
}

Prevention

When it happens

Trigger: lutils.NewSockPair("socket") returns an error: it cannot create/listen on the unix socket backing file, typically due to TMPDIR problems, too many open files, or permission issues in the temp directory.

Common situations: TMPDIR full or read-only so socketpair's temp socket path cannot be created; process hit the file-descriptor limit (ulimit -n) so socket creation fails EMFILE; SELinux/AppArmor blocking unix socket creation; /tmp cleaned by systemd-tmpfiles while sockets open (a known Nomad issue class).

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/30cab6a1f5ef189d. Report an issue: GitHub.