Hmbown/CodeWhale · warning

Auto has no concrete route yet; send a turn before warming…

Error message

Auto has no concrete route yet; send a turn before warming its cache

What it means

Thrown by resolve_cache_replay_route when cache warmup is requested for the Auto routing mode before Auto has resolved to any concrete provider route. Auto picks a route only after a real turn has been sent; with no turn history there is no concrete provider/endpoint to replay against, so warmup cannot proceed.

Solutions

  1. Send at least one turn normally first; Auto then records a concrete route and warmup succeeds.
  2. Pin the route to a specific provider/model instead of Auto if you need warmup before any turn.
  3. Skip warmup when app.cache_replay_target() is None rather than calling resolve_cache_replay_route.
  4. If a turn was already sent but the target is still None, check that route resolution persisted the last concrete route.

Example fix

// before
let route = resolve_cache_replay_route(app, config)?;
warm_cache(route).await?;
// after
if let Ok(route) = resolve_cache_replay_route(app, config) {
    warm_cache(route).await?;
} // else: Auto not yet resolved; skip warmup until first turn completes
Defensive patterns

Strategy: fallback

Validate before calling

// skip warmup when Auto has not resolved a concrete route
fn warmup_ready(app: &App) -> bool {
    app.cache_replay_target().is_some()
}

Try / catch

match resolve_cache_replay_route(app, config) {
    Ok(route) => warm_cache(route).await?,
    Err(e) if e.to_string().contains("no concrete route") => {
        tracing::debug!("skipping warmup: Auto not yet resolved");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling run_cache_warmup -> resolve_cache_replay_route while app.cache_replay_target() returns None — i.e. triggering prompt-cache warmup with route set to Auto in a fresh session with zero completed turns, or after state that cleared the last resolved route.

Common situations: Warming the cache immediately after launching a new session pinned to Auto; running warmup after clearing conversation history; scripts that invoke warmup before the first user turn completes.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/src/tui/ui/provider_routes.rs:401

}

pub(crate) async fn fetch_available_models(config: &Config) -> Result<Vec<String>> {
    use crate::client::CodewhaleClient;

    let client = CodewhaleClient::new(config)?;
    let models = tokio::time::timeout(Duration::from_secs(20), client.list_models()).await??;
    let mut ids = models.into_iter().map(|model| model.id).collect::<Vec<_>>();
    ids.sort();
    ids.dedup();
    Ok(ids)
}

pub(crate) fn resolve_cache_replay_route(
    app: &App,
    config: &Config,
) -> Result<crate::route_runtime::ResolvedRuntimeRoute> {
    let target = app.cache_replay_target().ok_or_else(|| {
        anyhow::anyhow!("Auto has no concrete route yet; send a turn before warming its cache")
    })?;
    let identity = config
        .resolve_persisted_provider_identity(
            Some(target.provider.as_str()),
            target.provider_id.as_deref(),
        )
        .map_err(anyhow::Error::msg)?;
    if identity.provider != target.provider || identity.key != target.provider_identity {
        anyhow::bail!(
            "saved cache route identity `{}` now resolves as {}/{} instead of {}/{}; send a new turn before warming",
            target.provider_identity,
            identity.provider.as_str(),
            identity.key,
            target.provider.as_str(),
            target.provider_identity
        );
    }
    let route = resolve_runtime_route_for_identity(config, &identity, Some(&target.model))

View on GitHub (pinned to 73e0f67d83)