gleam-lang/gleam · error
stdin read_line
Error message
stdin read_line
What it means
Panic from `.expect("stdin read_line")` in send_user_to_oauth_verification_url in compiler-cli/src/hex/auth.rs. Reading the user's Enter keypress from standard input failed — stdin was closed, redirected from an exhausted/EOF pipe, or an I/O error occurred — so the OAuth device flow panics instead of proceeding to open the browser.
Solutions
- Run the authentication command in an interactive terminal with stdin attached.
- Ignore read failures on stdin (the read is only a pause) instead of panicking: use `let _ = std::io::stdin().read_line(...)` without expect.
- Skip the pause entirely when stdin is not a TTY (check with std::io::stdin().is_terminal() via the IsTerminal trait) and open the browser immediately.
- Provide a non-interactive mode that prints the verification URL and code without waiting for Enter.
Example fix
// before
std::io::stdin()
.read_line(&mut String::new())
.expect("stdin read_line");
// after
if std::io::stdin().is_terminal() {
let _ = std::io::stdin().read_line(&mut String::new());
} Defensive patterns
Strategy: try-catch
Validate before calling
use std::io::IsTerminal;
if !std::io::stdin().is_terminal() { eprintln!("non-interactive: skipping Enter prompt"); } Type guard
fn stdin_is_interactive() -> bool { std::io::IsTerminal::is_terminal(&std::io::stdin()) } Try / catch
std::panic::catch_unwind(|| gleam_hex::authenticate())
.map_err(|_| anyhow::anyhow!("gleam auth panicked waiting on stdin"))?; Prevention
- Only run OAuth device flows in interactive terminals.
- Never redirect stdin from /dev/null when calling gleam auth.
- Make the prompt tolerant of read errors — it is only a pause.
- Offer a non-interactive flag that prints the URL without waiting.
When it happens
Trigger: Running the Hex OAuth authentication (`gleam auth`) non-interactively: stdin redirected from /dev/null or a closed pipe, running under CI where no TTY exists, or stdin read interrupted by an I/O error after the device code is displayed.
Common situations: CI pipelines invoking gleam auth without a TTY, scripts piping input to the CLI, detached processes whose stdin is closed, or containers run with `< /dev/null`.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
AI-assisted analysis of gleam-lang/gleam@15b07c7830 (2026-09-14).
Data as JSON: /api/errors/68ec3f41ae84571b.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-cli/src/hex/auth.rs:340
fn send_user_to_oauth_verification_url(device_authorisation: &hexpm::OAuthDeviceAuthorisation) {
// We make them press Enter to open the browser instead of going there immediately,
// to make sure they see the code before the browser window potentially hides the
// terminal window.
let uri = &device_authorisation.verification_uri;
println!(
"Your Hex verification code:
{code}
Verify this code matches what is shown in your browser.
Press Enter to open {uri}",
code = device_authorisation.user_code,
);
let _ = std::io::stdin()
.read_line(&mut String::new())
.expect("stdin read_line");
if opener::open_browser(uri).is_err() {
println!("\nFailed to open the browser, please navigate to {uri}");
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct StoredOAuthRepoCredentials {
#[serde(with = "http_serde::uri")]
api: http::Uri,
#[serde(with = "http_serde::uri")]
repository: http::Uri,
/// An encrypted refresh token.
refresh_token: String,
/// The hash of the token, so it can be revoked even if it cannot be encrypted.
refresh_token_hash: String,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]View on GitHub (pinned to 15b07c7830)