You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
In mac, terminal freezes when taking JWT token as getpass input #157538
Issue Title: Terminal freezes on macOS when passing a JWT token via getpass Summary
When attempting to input a long string—specifically a JSON Web Token (JWT)—using Python's getpass module in the macOS Terminal, the terminal application hangs and freezes completely, requiring a force quit.
Steps to Reproduce
Open Terminal (or iTerm2) on macOS.
Run a Python script or interactive shell that calls getpass.getpass().
Paste a standard long JWT string into the prompt.
Observe the terminal freeze/hang.
Expected Behavior
The terminal should accept the input securely (masking characters if applicable) without locking up, allowing the script to proceed.
Actual Behavior
The terminal interface stops responding entirely
@picnixz answering your two questions directly, and then handing this claim back — I can't do the reproduction you're asking for.
"getpass() is backed by readline or something else?" — not readline, on any path. I checked Lib/getpass.py at origin/main (b0dda158aa): import readline appears zero times in the module. All seven occurrences of the string are something else:
getpass binds to unix_getpass at module scope when import termios succeeds and tcgetattr/tcsetattr exist (Lib/getpass.py:450; the Windows binding is :448).
unix_getpass opens its own fd on /dev/tty with O_RDWR|O_NOCTTY (:91), wraps it in a TextIOWrapper, and the "readline" in _raw_input is line = input.readline() (:234) — the TextIOWrapper method on that fd, not the readline module. The comment at :215 ("This doesn't save the string in the GNU readline history") is deliberate.
The only character-at-a-time editor is CPython's own _PasswordLineEditor (:242-249, :384), and it is reached only when the caller passes echo_char=.
input() really is a different mechanism, so it isn't a like-for-like control: builtins input() goes through PyOS_Readline (Python/bltinmodule.c:2560, gated on isatty() at :2454), and the GNU module substitutes itself there via PyOS_ReadlineFunctionPointer = call_readline (Modules/readline.c:1878). So a plain input() test is still worth running — it separates "the pty write path wedges" from "something in the termios round-trip" — but an input() that behaves fine would not clear getpass(), because the two don't share a reader.
What in the code is consistent with the report (stated as reading, not as a repro): on the default getpass.getpass(prompt) call, unix_getpass clears onlyECHO (:114). ICANON (:121) and IEXTEN (:126) are cleared only inside if echo_char:. So a plain call leaves the tty in canonical mode and blocks in readline() until a newline arrives — which is the shape a pasted JWT (long, no trailing newline) would hit. That matches the diagnosis in #157805, including nouraellm's point about the canonical input queue limit; I have not verified the MAX_INPUT figure myself, that part is theirs.
Why I'm dropping the claim. My environment cannot exercise this path at all, and that is measured, not assumed: the local build here is 3.16.0a0 free-threaded on Windows, getpass.getpass resolves to win_getpass, and import termios raises ImportError — there is no macOS machine available to me. My claim on this issue was explicitly conditional on reproducing first ("I'll submit a PR if I can reproduce and identify the root cause"), so I should not sit on it.
nouraellm already wrote the non-canonical-mode fix in #157805 and it was closed while this issue still carried my name on it — that looks like the wrong outcome to me, so if you're open to it it's theirs to pick back up; @nouraellm sorry my stale claim blocked your PR, it's released above. If you'd rather keep it under investigation first, the piece that needs a Mac is small: paste a >1024-byte string with no newline at a plain getpass.getpass() prompt versus at input() with the same termios state, and note whether ICANON is what differs.
@Adarsh-Me Avoid LLM unedited answers that do not make the investigation forward. I am not interested in conversing with an agent with someone as a proxy
Yes but be careful. It is not just about reproducing it but about investigating this. We do not want to break anything on multiple platforms, nor do we want just switching to noncanon mode. You must first investigate the history of the module as there are subtleties and sometimes choices that we made in the past that we cannot always break.
Note that I do not wish any LLM generated PR for that. You can use an LLM to help investigating but do not write code through it and do not use it for addressing reviews (except for translations)
Activity
Adarsh-Me commentedon Sep 15, 2026
I'd like to work on this. I'll investigate the issue and submit a PR if I can reproduce and identify the root cause.
picnixz commentedon Sep 19, 2026
I wonder first if this is not just something with the terminal itself or the buffering maybe. Does it happen with plain input()?
picnixz commentedon Sep 19, 2026
getpass() is, I believe, backed by readline or something else in 3.13. Can you reproduce the issue in C?
Adarsh-Me commentedon Sep 23, 2026
@picnixz answering your two questions directly, and then handing this claim back — I can't do the reproduction you're asking for.
"getpass() is backed by readline or something else?" — not readline, on any path. I checked
Lib/getpass.pyatorigin/main(b0dda158aa):import readlineappears zero times in the module. All seven occurrences of the string are something else:getpassbinds tounix_getpassat module scope whenimport termiossucceeds andtcgetattr/tcsetattrexist (Lib/getpass.py:450; the Windows binding is :448).unix_getpassopens its own fd on/dev/ttywithO_RDWR|O_NOCTTY(:91), wraps it in aTextIOWrapper, and the "readline" in_raw_inputisline = input.readline()(:234) — theTextIOWrappermethod on that fd, not the readline module. The comment at :215 ("This doesn't save the string in the GNU readline history") is deliberate._PasswordLineEditor(:242-249, :384), and it is reached only when the caller passesecho_char=.input()really is a different mechanism, so it isn't a like-for-like control: builtinsinput()goes throughPyOS_Readline(Python/bltinmodule.c:2560, gated onisatty()at :2454), and the GNU module substitutes itself there viaPyOS_ReadlineFunctionPointer = call_readline(Modules/readline.c:1878). So a plaininput()test is still worth running — it separates "the pty write path wedges" from "something in the termios round-trip" — but aninput()that behaves fine would not cleargetpass(), because the two don't share a reader.What in the code is consistent with the report (stated as reading, not as a repro): on the default
getpass.getpass(prompt)call,unix_getpassclears onlyECHO(:114).ICANON(:121) andIEXTEN(:126) are cleared only insideif echo_char:. So a plain call leaves the tty in canonical mode and blocks inreadline()until a newline arrives — which is the shape a pasted JWT (long, no trailing newline) would hit. That matches the diagnosis in #157805, including nouraellm's point about the canonical input queue limit; I have not verified theMAX_INPUTfigure myself, that part is theirs.Why I'm dropping the claim. My environment cannot exercise this path at all, and that is measured, not assumed: the local build here is 3.16.0a0 free-threaded on Windows,
getpass.getpassresolves towin_getpass, andimport termiosraisesImportError— there is no macOS machine available to me. My claim on this issue was explicitly conditional on reproducing first ("I'll submit a PR if I can reproduce and identify the root cause"), so I should not sit on it.nouraellm already wrote the non-canonical-mode fix in #157805 and it was closed while this issue still carried my name on it — that looks like the wrong outcome to me, so if you're open to it it's theirs to pick back up; @nouraellm sorry my stale claim blocked your PR, it's released above. If you'd rather keep it under investigation first, the piece that needs a Mac is small: paste a >1024-byte string with no newline at a plain
getpass.getpass()prompt versus atinput()with the same termios state, and note whetherICANONis what differs.picnixz commentedon Sep 23, 2026
@Adarsh-Me Avoid LLM unedited answers that do not make the investigation forward. I am not interested in conversing with an agent with someone as a proxy
nouraellm commentedon Sep 24, 2026
@picnixz do you accept I tackle it? I can retest it in my mac (tho I remember being able to reproduce)
picnixz commentedon Sep 24, 2026
Yes but be careful. It is not just about reproducing it but about investigating this. We do not want to break anything on multiple platforms, nor do we want just switching to noncanon mode. You must first investigate the history of the module as there are subtleties and sometimes choices that we made in the past that we cannot always break.
nouraellm commentedon Sep 24, 2026
@picnixz crystal. Can you please assign the issue to me + reopen my PR to avoid any confusion with other contributors? thanks.
picnixz commentedon Sep 25, 2026
Note that I do not wish any LLM generated PR for that. You can use an LLM to help investigating but do not write code through it and do not use it for addressing reviews (except for translations)
nouraellm commentedon Sep 25, 2026
@picnixz This is not my first PR. I accept cash for apologies.