Hmbown/CodeWhale · error

{timeout_message}

Error message

{timeout_message}

What it means

The default branch of `timed_out`: when the device-code polling loop (`run`) exhausts its time budget without an explicit slow-down-specific message (either no slow_down occurred, or no `slow_down_timeout_message` is configured), the generic `timeout_message` is returned. This is the standard 'you took too long to authorize' error of the device flow.

Solutions

  1. Re-run the device-code login to get a fresh code and complete it within the expiry window.
  2. Authorize immediately after the code is displayed — codes typically expire within minutes.
  3. Avoid suspending the machine mid-login; if interrupted, restart the flow.
Defensive patterns

Strategy: retry

Try / catch

match auth.login_device_code() {
    Err(e) if e.to_string().contains("timed out") => {
        eprintln!("Device code expired; restarting login with a fresh code.");
        auth.login_device_code()?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: The device-code flow's polling loop reaches its overall expiry (user never entered the code, or polling ran past `expires_in`) — called from `run`.

Common situations: User abandoned the browser step, the verification code expired, or the machine was suspended during authorization.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/953721570941fda1. Report an issue: GitHub.

Appendix: source

Thrown at crates/config/src/device_code.rs:174

                    };
                }
            }

            // Never sleep past the code's expiry, even after slow_down backoff.
            let remaining = deadline.saturating_duration_since(Instant::now());
            if remaining.is_zero() {
                break;
            }
            sleep(interval.min(remaining));
        }

        Err(self.timed_out(saw_slow_down))
    }

    fn timed_out(&self, saw_slow_down: bool) -> anyhow::Error {
        match (saw_slow_down, self.slow_down_timeout_message.as_deref()) {
            (true, Some(message)) => anyhow::anyhow!("{message}"),
            _ => anyhow::anyhow!("{}", self.timeout_message),
        }
    }
}

/// Reject a device-code verification URI that must not be handed to a browser
/// opener.
///
/// Ported from pi's `validateVerificationUri`
/// (`packages/ai/src/auth/oauth/xai.ts`, MIT, Copyright (c) 2025 Mario
/// Zechner): the URI comes straight off the wire and is passed to the platform
/// "open this" call, so a malicious or compromised response could otherwise
/// launch `file:`, a custom app scheme, or a helper with attacker-chosen
/// arguments. pi requires `https:`; Codewhale additionally allows `http:` on a
/// loopback host, which is what self-hosted issuers and the device-code tests
/// use — matching the loopback allowance the account login already makes.
///
/// Embedded credentials are rejected in every case.
pub fn validate_browser_verification_uri(raw: &str, context: &str) -> Result<String> {

View on GitHub (pinned to 73e0f67d83)