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

  1. Run the authentication command in an interactive terminal with stdin attached.
  2. Ignore read failures on stdin (the read is only a pause) instead of panicking: use `let _ = std::io::stdin().read_line(...)` without expect.
  3. 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.
  4. 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

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)