{"record":{"id":"54fdeba27ea1f0d0","repo":"denoland/deno","slug":"err-tty-init-failed-54fdeb","errorCode":"ERR_TTY_INIT_FAILED","errorMessage":"TTY initialization failed: ${ctx.syscall} returned ${ctx.code} (${ctx.message})","messagePattern":"TTY initialization failed: (.+?) returned (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"SystemError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/tty_esm.ts","lineNumber":41,"sourceCode":"// deno-lint-ignore no-explicit-any\nfunction ReadStream(this: any, fd: number, options?: unknown) {\n  if (!ObjectPrototypeIsPrototypeOf(ReadStream.prototype, this)) {\n    // deno-lint-ignore no-explicit-any\n    return new (ReadStream as any)(fd, options);\n  }\n\n  if (fd >> 0 !== fd || fd < 0) {\n    throw new ERR_INVALID_FD(fd);\n  }\n\n  // Non-stdio fds require --allow-all\n  op_tty_check_fd_permission(fd);\n\n  // deno-lint-ignore no-explicit-any\n  const ctx: any = {};\n  const tty = new TTY(fd, ctx);\n  if (ctx.code !== undefined) {\n    throw new ERR_TTY_INIT_FAILED(ctx);\n  }\n  FunctionPrototypeCall(Socket, this, {\n    readableHighWaterMark: 0,\n    handle: tty,\n    manualStart: true,\n    // deno-lint-ignore no-explicit-any\n    ...(options as any),\n  });\n\n  this.isRaw = false;\n  this.isTTY = true;\n}\n\nObjectSetPrototypeOf(ReadStream.prototype, Socket.prototype);\nObjectSetPrototypeOf(ReadStream, Socket);\n\n// deno-lint-ignore no-explicit-any\n(ReadStream as any).prototype.setRawMode = function setRawMode(","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/tty_esm.ts#L23-L59","documentation":"tty.ReadStream creation wraps a native TTY operation; if that syscall fails, the error context (syscall name, errno, OS message) is wrapped in ERR_TTY_INIT_FAILED — e.g. an ioctl like TCGETS returning ENOTTY when the fd is a pipe rather than a terminal, or EBADF for a closed fd. The message reports syscall, code and OS message so the failing operation is identifiable.","triggerScenarios":"`new tty.ReadStream(1)` while stdout is piped (`app | cat`, CI logs, redirects); wrapping an fd that was already closed; opening /dev/null or a socket and treating that fd as a tty.","commonSituations":"Color/interactive CLI code run under CI or cron without a terminal; Docker/Kubernetes containers started without tty allocation; scripts that worked on a dev terminal but fail when output is redirected.","solutions":["Check `tty.isatty(fd)` before constructing the ReadStream","Catch ERR_TTY_INIT_FAILED and degrade to non-interactive output (no colors, no raw mode)","Allocate a pty in CI when tty behavior must be tested (`script -c` on Linux)","Do not construct ReadStream around fds your code has already closed"],"exampleFix":"// before\nconst rs = new tty.ReadStream(fd); // throws when fd is a pipe (CI, redirects)\n\n// after\nif (tty.isatty(fd)) {\n  const rs = new tty.ReadStream(fd);\n} else {\n  // not a terminal: keep plain stream behavior\n  process.stdout.write(\"output (no tty)\\n\");\n}","handlingStrategy":"validation","validationCode":"if (!tty.isatty(fd)) {\n  // pipe or file: skip TTY setup, use plain stream behavior\n  plainMode = true;\n} else {\n  const rs = new tty.ReadStream(fd);\n}","typeGuard":"const isTerminal = (fd: number): boolean => {\n  try {\n    return tty.isatty(fd);\n  } catch {\n    return false;\n  }\n};","tryCatchPattern":"try {\n  const rs = new tty.ReadStream(fd);\n} catch (e: any) {\n  if (e?.code === \"ERR_TTY_INIT_FAILED\") {\n    plainMode = true; // degrade to non-interactive output\n  } else {\n    throw e;\n  }\n}","preventionTips":["Call tty.isatty(fd) before creating tty streams","Make interactive features optional so piped/CI runs work","Use a pty wrapper (script -c) when TTY paths must be tested","Never wrap fds your process has already closed"],"tags":["tty","terminal","node-compat","system-error"],"backgroundTag":"not-a-terminal","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-26T07:17:17.940Z"}