{"record":{"id":"e8bbc589a4b88e14","repo":"git-ecosystem/git-credential-manager","slug":"failed-to-read-initial-terminal-settings","errorCode":null,"errorMessage":"Failed to read initial terminal settings.","messagePattern":"Failed to read initial terminal settings\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/Core/Interop/Linux/LinuxAnsiConsoleInput.cs","lineNumber":33,"sourceCode":"\n    protected override IDisposable EnterRawMode(PosixFileDescriptor fd)\n    {\n        return new RawModeContext(fd);\n    }\n\n    private sealed class RawModeContext : IDisposable\n    {\n        private readonly int _fd;\n        private termios_Linux _original;\n        private bool _isDisposed;\n\n        public RawModeContext(int fd)\n        {\n            _fd = fd;\n\n            if (Termios_Linux.tcgetattr(_fd, out termios_Linux t) != 0)\n            {\n                throw new System.IO.IOException(\"Failed to read initial terminal settings.\");\n            }\n\n            _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","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/Core/Interop/Linux/LinuxAnsiConsoleInput.cs#L15-L51","documentation":"LinuxAnsiConsoleInput.RawModeContext captures the terminal's current termios settings via tcgetattr so they can be restored after raw mode; if the tcgetattr syscall fails (non-zero return) the constructor throws IOException. Without the original settings the code cannot safely enter or later restore raw mode.","triggerScenarios":"Constructing RawModeContext(fd) when tcgetattr fails — fd is not a TTY (piped stdin, redirected output), fd is invalid/closed, or running in an environment without a controlling terminal.","commonSituations":"Running GCM's interactive prompts under CI, piping input (echo | gcm), running inside an IDE console or systemd service without a TTY, or docker run without -t.","solutions":["Run the tool in a real terminal (allocate a TTY: docker run -t, script/expect in CI)","Check Isatty/Console.IsInputRedirected before requesting raw mode and fall back to non-interactive input","Verify the fd passed to RawModeContext is the terminal's stdin (0) and still open","For non-interactive environments, supply credentials via config/environment instead of terminal prompts"],"exampleFix":"// before\nusing var raw = new RawModeContext(fd); // throws when stdin is piped\n// after\nif (Console.IsInputRedirected || !IsATty(fd))\n    throw new InvalidOperationException(\"Interactive terminal required; run in a TTY or use non-interactive auth.\");\nusing var raw = new RawModeContext(fd);","handlingStrategy":"try-catch","validationCode":"if (Console.IsInputRedirected)\n    throw new InvalidOperationException(\"Raw terminal mode requires an interactive TTY; stdin is redirected.\");","typeGuard":"bool CanUseRawMode(int fd) => !Console.IsInputRedirected && LinuxAnsiConsoleInput.IsATty(fd);","tryCatchPattern":"try\n{\n    using var raw = new RawModeContext(fd);\n    // interactive prompt\n}\ncatch (IOException ex) when (ex.Message == \"Failed to read initial terminal settings.\")\n{\n    logger.LogWarning(\"No TTY available; falling back to non-interactive authentication\");\n}","preventionTips":["Check IsInputRedirected / isatty before enabling raw mode and provide a non-interactive fallback","Allocate a TTY in CI/containers (docker run -t, script -c) when interactive prompts are needed","Offer environment/config-based credentials so prompts are never required in headless environments"],"tags":["terminal","tty","linux","raw-mode","interop"],"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"}