gleam-lang/gleam · critical

stdin read_line

Error message

stdin read_line

What it means

In the Hex OAuth device flow, Gleam prints a verification code and waits for the user to press Enter before opening the browser (compiler-cli/src/hex/auth.rs:340). It calls `std::io::stdin().read_line(&mut String::new()).expect("stdin read_line")`. Because the bytes are appended into a `String`, `read_line` returns Err (not EOF) when stdin delivers invalid UTF-8, or when stdin is a closed/bad file descriptor; the expect then aborts the login. A clean EOF (Ctrl-D, </dev/null) is Ok(0) and does NOT trigger this.

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 7e623aa83d)

Solutions

  1. Run the command interactively in a terminal and press Enter at the prompt
  2. For non-interactive use, pipe clean UTF-8 input: `echo | gleam hex authenticate` (a single newline is all it needs)
  3. Point stdin at /dev/null (`gleam hex authenticate < /dev/null`) instead of leaving a closed fd or binary pipe
  4. Fix CI wrappers that close fd 0 so stdin is a valid pipe or file

Example fix

# before: binary piped to stdin -> read_line InvalidData -> panic 'stdin read_line'
cat data.bin | gleam hex authenticate

# after: valid UTF-8 newline satisfies the prompt
echo | gleam hex authenticate
Defensive patterns

Strategy: validation

Validate before calling

# non-interactive wrapper: give the Enter prompt a clean UTF-8 newline
if [ -t 0 ]; then
  gleam hex authenticate
else
  echo | gleam hex authenticate
fi

Prevention

When it happens

Trigger: Running `gleam hex authenticate` (or the OAuth prompt reached from `gleam publish`) with non-UTF-8 bytes piped to stdin (e.g. `gleam hex authenticate < data.bin`), or under a wrapper where fd 0 is closed or invalid (some CI steps, daemonized processes).

Common situations: Automation that pipes files into every command; CI jobs with closed stdin; a previous pipe stage emitting binary garbage; here-documents containing non-UTF-8 bytes used to 'answer' the prompt.

Related errors


AI-assisted analysis of gleam-lang/gleam@7e623aa83d (2026-08-17). Data as JSON: /api/errors/68ec3f41ae84571b. Report an issue: GitHub.