jdx/mise · error

relay unavailable

Error message

relay unavailable

What it means

tool_stub resolves a tool request into a Toolset, then requires that the resolved toolset exposes at least one current version via toolset.list_current_versions(). If the resolution produced an empty set of current versions, mise cannot proceed to install or exec the stub tool and throws this error. It signals that the requested tool/version resolved to nothing usable.

Source

Thrown at src/github_relay.rs:809

                            builder = builder.header(name, value);
                        }
                    }
                    let stream = futures_util::stream::try_unfold(
                        (response, permit),
                        |(mut response, permit)| async move {
                            let chunk = response
                                .chunk()
                                .await
                                .map_err(|_| std::io::Error::other("relay disconnected"))?;
                            Ok::<_, std::io::Error>(chunk.map(|chunk| (chunk, (response, permit))))
                        },
                    );
                    Ok(builder.body(Body::from_stream(stream))?)
                }
                .await;
                result.unwrap_or_else(|_| {
                    Response::builder()
                        .status(403)
                        .body(Body::from("relay unavailable"))
                        .expect("valid response")
                })
            }
        });
        let task = tokio::spawn(async move {
            let _ = axum::serve(BoundedListener::new(listener), service).await;
        });
        // Aborting this task is sufficient here: exiting the adapter also closes
        // all accepted loopback connections. Local broker cancellation is separate.
        let guard = AbortTask(task);
        let mut child = if command.is_empty() {
            let shell = std::env::var_os("SHELL").unwrap_or_else(|| "/bin/sh".into());
            let mut child = tokio::process::Command::new(shell);
            child.arg("-l");
            child
        } else {
            let mut child = tokio::process::Command::new(&command[0]);

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Check the requested version spec for typos: run `mise ls-remote <tool>` to see valid versions
  2. Fix the version in the config file (mise.toml / .tool-versions) to a resolvable version
  3. Run `mise reshim` / `mise install` to refresh installed state and shims
  4. Verify the backend for the tool is configured and can list versions

Example fix

// before
mise exec node@99.0.0 -- node -v

// after
mise exec node@22 -- node -v
Defensive patterns

Strategy: validation

Validate before calling

mise ls-remote <tool> | grep -Fx "<version>" || echo "version not available"

Prevention

When it happens

Trigger: Calling execute_with_tool_request (via run) where after resolving the ToolRequest, toolset.list_current_versions() returns an empty list — e.g. the requested version matches no available release.

Common situations: Typo'd or nonexistent tool version passed to a shim; a tool configured with a version prefix that matches nothing; registry/backend changes removing the pinned version; running `mise x tool@weirdversion` with an unresolvable spec.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/cce2a76231028bb5. Report an issue: GitHub.