jdx/mise · error
semaphore closed
Error message
semaphore closed
What it means
The Go proxy version-info fetch spawns a task per version, each awaiting `sem.acquire_owned()`. `acquire_owned` only fails with `acquire closed`, meaning the semaphore was dropped while permits were still being awaited. The panic indicates the shared semaphore's lifetime ended before the spawned tasks finished — an internal concurrency bug.
Source
Thrown at src/backend/go.rs:751
}
async fn fetch_proxy_version_infos(
proxies: &[GoProxy],
path: &str,
versions: &[String],
) -> Vec<VersionInfo> {
let encoded = Arc::new(encode_module_path(path));
let proxies = Arc::new(proxies.to_vec());
let sem = Arc::new(Semaphore::new(GO_PROXY_VERSION_INFO_CONCURRENCY));
let mut join_set = tokio::task::JoinSet::new();
for version in versions {
let proxies = proxies.clone();
let encoded = encoded.clone();
let sem = sem.clone();
let version = version.clone();
join_set.spawn(async move {
let _permit = sem.acquire_owned().await.expect("semaphore closed");
let endpoint = format!("{encoded}/@v/{version}.info");
let info = query_proxy_version_metadata(proxies.as_slice(), &endpoint).await;
(version, info)
});
}
let mut times = BTreeMap::new();
while let Some(result) = join_set.join_next().await {
match result {
Ok((version, ProxyVersionInfoResult::Found(info))) => {
times.insert(version, info.time);
}
Ok((version, ProxyVersionInfoResult::NotFound | ProxyVersionInfoResult::Error)) => {
times.insert(version, None);
}
Err(e) => warn!("proxy version info task panicked: {e}"),
}
}View on GitHub (pinned to afd2eddd3a)
Solutions
- Update mise to the latest version where the semaphore lifetime is correct
- Retry the command — a transient cancellation path may have triggered it
- File a bug with the backtrace if reproducible
Example fix
// before
let sem = Arc::new(Semaphore::new(limit)); // dropped before tasks run
// after
let sem = Arc::new(Semaphore::new(limit));
let join_set = { /* spawn all tasks holding sem.clone() */ };
while let Some(res) = join_set.join_next().await { /* ... */ } // sem outlives tasks Defensive patterns
Strategy: retry
Try / catch
mise ls-remote go || { echo 'transient proxy listing failure — retry'; mise ls-remote go; } Prevention
- Keep mise updated — semaphore lifecycle bugs are fixed upstream
- Retry transient failures during parallel version listing
- Report reproducible cases with backtrace; this is an internal concurrency invariant
When it happens
Trigger: `fetch_proxy_version_infos` (called by `fetch_proxy_versions` when listing Go module proxy versions) with a `sem` that is dropped or closed before `join_set` tasks complete — e.g. a refactor moves `sem` into a shorter-lived scope, or cancellation drops the semaphore early.
Common situations: Not reachable through user configuration; appears only with concurrency lifecycle bugs in the Go backend's parallel proxy queries, possibly under cancellation/timeouts during `mise install go` version listing.
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
- missing arg order for {}
- Go workspace module {} is missing {GO_MOD}
- BootstrapPart values have clap names
- bootstrap command is registered
- affected project exists in graph
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/891b71fdad2df88f.
Report an issue: GitHub.