{"record":{"id":"d42a4337c6142f3d","repo":"git-ecosystem/git-credential-manager","slug":"failed-to-enter-raw-terminal-mode-d42a43","errorCode":null,"errorMessage":"Failed to enter raw terminal mode.","messagePattern":"Failed to enter raw terminal mode\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/Core/Interop/MacOS/MacOSAnsiConsoleInput.cs","lineNumber":54,"sourceCode":"            _original = t;\n\n            // Raw mode: disable echo, line buffering, and signal interpretation.\n            // With ISIG off the terminal does not generate SIGINT, so Ctrl+C\n            // arrives as a 0x03 byte that the base adapter reads and acts on\n            // directly. This is robust to GCM not being the terminal's\n            // foreground process group.\n            //\n            // TCSANOW (apply immediately) rather than TCSAFLUSH: this context\n            // is entered and disposed around each keystroke read, so the\n            // terminal is only raw while we are actively reading. Flushing on\n            // every transition would discard typeahead still queued in the tty\n            // buffer (e.g. the trailing Enter of a pasted \"<down><enter>\"),\n            // hanging the next read.\n            t.c_lflag &= ~(LocalFlags.ECHO | LocalFlags.ICANON | LocalFlags.ISIG);\n\n            if (Termios_MacOS.tcsetattr(_fd, SetActionFlags.TCSANOW, ref t) != 0)\n            {\n                throw new System.IO.IOException(\"Failed to enter raw terminal mode.\");\n            }\n        }\n\n        public void Dispose()\n        {\n            if (_isDisposed) return;\n            Termios_MacOS.tcsetattr(_fd, SetActionFlags.TCSANOW, ref _original);\n            _isDisposed = true;\n        }\n    }\n}\n","sourceCodeStart":36,"sourceCodeEnd":66,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/Core/Interop/MacOS/MacOSAnsiConsoleInput.cs#L36-L66","documentation":"Thrown by MacOSAnsiConsoleInput.RawModeContext when the tcsetattr() syscall fails to apply raw terminal settings (echo, canonical mode, and signal interpretation disabled) to the stdin file descriptor. The library needs raw mode to read individual keystrokes for interactive prompts; if the OS refuses the change, no interactive terminal input can be taken. This is an IOException from direct P/Invoke into macOS termios.","triggerScenarios":"Calling EnterRawMode (via interactive prompt input paths, e.g. reading a single key) when the passed fd is not a real TTY — e.g. stdin redirected from a file or pipe, a closed/invalid fd, or running under an environment that does not own the controlling terminal.","commonSituations":"Running git credential prompts with stdin redirected ('git ... < file' or piped input), executing under a daemon/CI job with no controlling TTY, invoking from IDE terminals or wrappers that intercept stdin, or ssh sessions without a pseudo-terminal allocated (ssh -T / non-interactive).","solutions":["Ensure stdin is an interactive TTY before invoking the credential prompt; check with `tty` or isatty and fall back to non-interactive auth (credential helper store, env var, or cached OAuth token)","Run the command in a real terminal session with a controlling TTY; for ssh use `ssh -t` to allocate a pseudo-terminal","Redirect the interactive prompt's input: use GCM_INTERACTIVE=never / --no-interactive (or provide credentials non-interactively) so raw mode is never entered","Verify the file descriptor is valid and open (fd not closed by a parent process or sandbox) before the prompt runs"],"exampleFix":"// before\ngit credential fill < credentials.txt   # stdin is not a TTY -> tcsetattr fails\n// after\ntty < /dev/tty && git credential fill   # run only when a real terminal is attached\n# or force non-interactive mode\nexport GCM_INTERACTIVE=never","handlingStrategy":"try-catch","validationCode":"using System;\nusing System.IO;\n\nstatic bool StdinIsInteractive()\n{\n    try\n    {\n        // On POSIX a redirected/absent TTY cannot be put into raw mode.\n        // Check via Mono.Posix / native isatty, or env heuristics:\n        return !Console.IsInputRedirected && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable(\"TERM\"));\n    }\n    catch { return false; }\n}\n\nif (!StdinIsInteractive())\n{\n    // skip interactive prompt; use non-interactive credential source\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    // interactive prompt path that enters raw mode\n    string password = promptForPassword();\n}\ncatch (IOException ex) when (ex.Message.Contains(\"Failed to enter raw terminal mode\"))\n{\n    // stdin is not a TTY — fall back to non-interactive credential lookup\n}\n","preventionTips":["Check Console.IsInputRedirected (or isatty) before triggering interactive prompts","Set GCM_INTERACTIVE=never in CI, scripts, and daemon contexts","For SSH automation, allocate a TTY with `ssh -t` or avoid interactive auth entirely","Never pipe or redirect stdin into commands that may trigger a credential prompt"],"tags":["macos","terminal","raw-mode","interop","io"],"backgroundTag":"unsupported-platform","analyzedSha":"e8ce762cd04b4100ae637b5fbf39ef9d0a96561e","analyzedAt":"2026-09-11T17:15:08.753Z","contentChangedAt":"2026-09-11T17:15:08.753Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}