atuinsh/atuin · error

model list request failed

Error message

model list request failed ({status})

What it means

`fetch_models` in atuin-ai requests the model list from the Atuin AI backend and fails when the HTTP response status is not a success. The status code is interpolated into the message, e.g. `model list request failed (500 Internal Server Error)`.

Solutions

  1. Read the status code in the message: 401/403 → re-authenticate (`atuin login` or refresh session)
  2. Retry after confirming https://status.atuin.dev or backend availability
  3. Check network/proxy configuration
  4. Verify your Atuin version is current — API endpoints change
Defensive patterns

Strategy: retry

Validate before calling

// pre-check: only call with a live session and reachable backend
if atuin_client::hub::HubAuthSession::is_expired(&session) {
    session = refresh_session().await?;
}

Try / catch

match fetch_models(&client, &token).await {
    Ok(models) => models,
    Err(e) if e.to_string().contains("401") => reauth_then_retry().await?,
    Err(e) if e.to_string().contains("5") => backoff_retry(3).await?,
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `fetch_models` when the backend returns 4xx/5xx — invalid or expired bearer token, backend outage, or network intermediary error.

Common situations: Expired sync/AI session token causing 401, Atuin AI service downtime, or a proxy returning 502.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19). Data as JSON: /api/errors/fefbd75ca96cc296. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin-ai/src/models.rs:44

}

/// Fetch the models available to this user. Sent authenticated because the
/// server includes feature-flag-gated models only for entitled users.
pub async fn fetch_models(endpoint: &reqwest::Url, token: &str) -> Result<ModelList> {
    let url = endpoint.append_path("api/cli/models")?;

    let mut request = reqwest::Client::new()
        .get(url)
        .header(USER_AGENT, crate::stream::APP_USER_AGENT)
        .timeout(Duration::from_secs(10));
    if !token.is_empty() {
        request = request.bearer_auth(token);
    }
    let response = request.send().await.context("failed to fetch model list")?;

    let status = response.status();
    if !status.is_success() {
        eyre::bail!("model list request failed ({status})");
    }

    response.json::<ModelList>().await.context("failed to parse model list")
}

/// Persist the chosen alias to `ai.model` in config.toml so it becomes the
/// default for future sessions. Already-running sessions keep the model they
/// read at startup.
pub async fn save_model_selection(alias: &str) -> Result<()> {
    let config_file = atuin_client::settings::Settings::get_config_path()?;
    let config_str = tokio::fs::read_to_string(&config_file).await.unwrap_or_default();
    let mut doc = config_str.parse::<toml_edit::DocumentMut>()?;

    if !doc.contains_key("ai") {
        doc["ai"] = toml_edit::table();
    }
    doc["ai"]["model"] = toml_edit::value(alias);

View on GitHub (pinned to 900007c480)