astrid-runtime/astrid · error
model discovery thread panicked
Error message
model discovery thread panicked
What it means
fetch_options_blocking runs fetch_options on a dedicated thread with its own tokio runtime; if that thread panics, the join() returns Err and this error is raised instead. It converts an internal panic into a user-facing anyhow error so the caller can fall back to free-text input.
Solutions
- Re-run the command; if reproducible, capture the panic backtrace (RUST_BACKTRACE=1) and report the underlying bug
- Upgrade astrid-cli to get fixes in the discovery path
- Bypass interactive discovery and enter the model name manually via the fallback
- Check environment restrictions that could make the runtime builder or blocking thread fail
Defensive patterns
Strategy: try-catch
Try / catch
let options = match fetch_options_blocking(opts, values) {
Ok(o) => o,
Err(e) if e.to_string().contains("thread panicked") => {
eprintln!("model discovery failed; enter the model name manually.");
vec![prompt_free_text()?
}
Err(e) => return Err(e),
}; Prevention
- Keep astrid-cli updated to pick up discovery-path fixes
- Report reproducible panics with RUST_BACKTRACE=1 output
- Treat interactive discovery as best-effort and always provide a manual entry fallback
When it happens
Trigger: A panic inside fetch_options or its dependencies (e.g. reqwest/tokio runtime bug, unwraps in parsing) while executing on the discovery thread.
Common situations: Upstream library panics on malformed responses; platform/runtime incompatibilities (e.g. sandboxed environments blocking thread spawn features); genuine bugs in model discovery code.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- alice
- empty page deserializes
- failed to spawn hook epoch ticker
- non-empty audit
- OS CSPRNG unavailable while generating default keypair name
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/da5a59d4a9927b75.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-cli/src/commands/capsule/model_discovery.rs:334
/// before returning, keeping the prompt strictly sequential.
///
/// Returns `Err` on any failure (mirroring [`fetch_options`]); the caller
/// maps that to a free-text fallback.
pub(crate) fn fetch_options_blocking(
opts: &OptionsFrom,
values: &HashMap<String, String>,
) -> anyhow::Result<Vec<String>> {
std::thread::scope(|scope| {
scope
.spawn(|| {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.context("failed to build discovery runtime")?;
runtime.block_on(fetch_options(opts, values))
})
.join()
.map_err(|_| anyhow::anyhow!("model discovery thread panicked"))?
})
}
#[cfg(test)]
mod tests {
use super::*;
fn vals(pairs: &[(&str, &str)]) -> HashMap<String, String> {
pairs
.iter()
.map(|(k, v)| ((*k).to_string(), (*v).to_string()))
.collect()
}
#[test]
fn resolve_template_substitutes_known_keys() {
let v = vals(&[("base_url", "https://api.openai.com"), ("api_key", "sk-x")]);
assert_eq!(View on GitHub (pinned to affd8760f4)