{"record":{"id":"9d4aed36f2cd8f42","repo":"FiloSottile/age","slug":"standard-input-is-not-a-terminal-and-dev-tty-is","errorCode":null,"errorMessage":"standard input is not a terminal, and /dev/tty is not available: %v","messagePattern":"standard input is not a terminal, and /dev/tty is not available: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/term/term.go","lineNumber":71,"sourceCode":"\tif runtime.GOOS == \"windows\" {\n\t\tin, err := os.OpenFile(\"CONIN$\", os.O_RDWR, 0)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer in.Close()\n\t\tout, err := os.OpenFile(\"CONOUT$\", os.O_WRONLY, 0)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer out.Close()\n\t\treturn f(in, out)\n\t} else if tty, err := os.OpenFile(\"/dev/tty\", os.O_RDWR, 0); err == nil {\n\t\tdefer tty.Close()\n\t\treturn f(tty, tty)\n\t} else if term.IsTerminal(int(os.Stdin.Fd())) {\n\t\treturn f(os.Stdin, os.Stdin)\n\t} else {\n\t\treturn fmt.Errorf(\"standard input is not a terminal, and /dev/tty is not available: %v\", err)\n\t}\n}\n\n// ReadSecret reads a value from the terminal with no echo. The prompt is ephemeral.\nfunc ReadSecret(prompt string) (s []byte, err error) {\n\terr = WithTerminal(func(in, out *os.File) error {\n\t\tprintPrompt(out, prompt)\n\t\tdefer clearLine(out)\n\t\ts, err = term.ReadPassword(int(in.Fd()))\n\t\treturn err\n\t})\n\treturn\n}\n\n// ReadPublic reads a value from the terminal. The prompt is ephemeral.\nfunc ReadPublic(prompt string) (s []byte, err error) {\n\terr = WithTerminal(func(in, out *os.File) error {\n\t\tprintPrompt(out, prompt)","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/internal/term/term.go#L53-L89","documentation":"term.WithTerminal needs a terminal for interactive input. It first tries os.Stdin, then falls back to opening /dev/tty. This error means stdin is not a terminal AND /dev/tty could not be opened (err is the open failure). age's interactive prompts (secrets, confirmations) cannot proceed without a TTY, so the operation fails instead of reading from a non-interactive source.","triggerScenarios":"Calling ReadSecret/ReadPublic/ReadCharacter/printfToTerminal (which go through WithTerminal) in an environment where stdin is a pipe/file (not a TTY) and /dev/tty is absent or unopenable: cron/systemd services, CI without a TTY allocation, containers without a controlling terminal, or environments where /dev/tty permissions deny access.","commonSituations":"Running age decrypt in a script with piped stdin when the tool requires TTY input; Docker containers without -t; CI pipelines without a pseudo-TTY; ssh sessions with stdin redirected; minimal images lacking /dev/tty.","solutions":["Provide the input non-interactively: pipe the secret or use age's key-file/identities options.","Allocate a TTY: run the command in docker run -t, ssh -tt, or a CI step with a TTY action.","Ensure /dev/tty exists and is accessible in the container (mount devtmpfs, fix permissions).","Restructure the automation to pass the passphrase via an identities/key file instead of terminal input.","Check the embedded %v error for why /dev/tty open failed (ENOENT vs EACCES) and fix that specific cause."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Detect TTY availability before invoking interactive APIs\nfunc hasTerminal() bool {\n    if term.IsTerminal(int(os.Stdin.Fd())) { return true }\n    f, err := os.OpenFile(\"/dev/tty\", os.O_RDWR, 0)\n    if err == nil { f.Close(); return true }\n    return false\n}","typeGuard":null,"tryCatchPattern":"if !hasTerminal() {\n    // use non-interactive path: key file, env var, or pre-provided secret\n    return runNonInteractive()\n}\nerr = term.ReadSecret(prompt) // may still fail; handle the /dev/tty error","preventionTips":["Always provide a non-interactive input path for scripts, CI, and containers.","Allocate a TTY (docker -t, ssh -tt) when interaction is required.","Ensure /dev/tty exists and is accessible in minimal container images.","Prefer identity/key files over typed passphrases in automation."],"tags":["terminal","tty","interactive-input","environment","go"],"backgroundTag":"no-tty-available","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}