Hmbown/CodeWhale · error
translation credential or endpoint changed after turn…
Error message
translation credential or endpoint changed after turn dispatch; refusing stale completion ownership
What it means
As a second, finer check after identity/model/endpoint match, `exact_translation_client` compares the client's `turn_route_receipt` for the provider identity against the receipt recorded at dispatch. A mismatch means the credential or endpoint details changed (e.g. API key rotated, endpoint credential updated) even though the identity is the same, so stale completion ownership is refused.
Solutions
- Re-authenticate or re-enter credentials, then start a new turn so a fresh receipt is captured
- Avoid rotating API keys or endpoint credentials while a turn is in progress
- If this happens on every turn, check for something rewriting credentials (e.g. a config sync tool) each turn
Defensive patterns
Strategy: validation
Validate before calling
if let Some(receipt) = route.receipt.as_ref()
&& &validated.client.turn_route_receipt(&route.provider_identity) != receipt {
eprintln!("credentials changed mid-turn; re-auth and start a new turn");
return;
} Type guard
fn receipt_current(c: &ProviderClient, r: &TurnRoute) -> bool {
r.receipt.as_ref().map_or(true, |want| {
&c.turn_route_receipt(&r.provider_identity) == want
})
} Try / catch
match exact_translation_client(...).await {
Err(e) if e.to_string().contains("credential or endpoint changed") => {
reauthenticate();
restart_turn();
}
r => r,
} Prevention
- Schedule API-key rotation and endpoint changes between turns, never mid-turn
- Disable credential-sync tools from rewriting keys during active sessions
- Capture a fresh route receipt whenever credentials change instead of reusing the old one
When it happens
Trigger: Calling `exact_translation_client` when `route.receipt` is set but `validated.client.turn_route_receipt(&route.provider_identity)` returns a different value — credential rotation, re-auth, or endpoint configuration change after the turn was dispatched.
Common situations: API key refreshed in another window/process mid-turn; auth token expired and re-authenticated during a long turn; managed credential store rotated keys while the turn was in flight.
Related errors
- Antigravity cloud-code HTTP
- API key not found. Run 'codewhale auth set --provider '…
- app-server auth token cannot be empty
- Cloud agents are not available for this account yet; cloud…
- Cloud agents are not available for this account yet; cloud…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/1508d18f3f40a3d3.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/ui/event_loop.rs:323
)
.map_err(anyhow::Error::msg)?
.validate()
.map_err(anyhow::Error::msg)?;
if validated.identity.key != route.provider_identity
|| validated.model != route.model
|| validated.candidate.endpoint().base_url != route.base_url
{
anyhow::bail!(
"translation route changed after turn dispatch; refusing to reuse a different provider client"
);
}
if let Some(receipt) = route.receipt.as_ref()
&& &validated
.client
.turn_route_receipt(&route.provider_identity)
!= receipt
{
anyhow::bail!(
"translation credential or endpoint changed after turn dispatch; refusing stale completion ownership"
);
}
Ok(Arc::new(validated.client))
}
/// Bind the Runtime thread store to a session before the process-owner lock
/// is taken, so a second Codewhale on the same machine does not collide on
/// the default root (#5630). This id is only the initial store anchor; saved
/// metadata retains the actual store binding when launch creates a new id.
pub(crate) fn ensure_runtime_session_id(app: &mut App) -> String {
if let Some(existing) = app
.current_session_id
.as_deref()
.map(str::trim)
.filter(|id| !id.is_empty())
{
return existing.to_string();View on GitHub (pinned to 73e0f67d83)