tracel-ai/burn · error
Service call failed
Error message
Service call failed
What it means
`RemoteClient::ensure_connected` submits a blocking connect/handshake task to the remote service's runner thread via `handle.submit_blocking(...)` and unwraps the returned Option with `expect("Service call failed")`. The service call channel returns `None` when the service/runner is shut down or the submission fails (channel closed), so the unwrap panics. It signals that the background service backing this client is no longer alive.
Source
Thrown at crates/burn-remote/src/client/base.rs:32
impl RemoteClient {
pub fn init(device: RemoteDevice) -> Self {
// `DeviceHandle::new` initializes the service the first time it's called for a given
// device id. `RemoteService::init` is deliberately cheap — it records the endpoint but
// does NOT connect, because cubecl holds a process-global lock across it; the actual
// connect + handshake happens lazily on first use (or via `ensure_connected`).
// Subsequent calls return a handle to the existing service.
let handle = DeviceHandle::<RemoteService>::new(device.to_id());
Self { device, handle }
}
/// Force the lazily-established connection to be opened now, populating the device's
/// settings/device-count cells. Used by the settings path (`RemoteDevice::defaults` /
/// `enumerate`), which needs the handshake reply before any op has flushed. Runs the
/// connect on the service's runner thread, so it can't sit under cubecl's global lock.
pub(crate) fn ensure_connected(&self) {
self.handle
.submit_blocking(|s| s.ensure_connected())
.expect("Service call failed");
}
/// Establish the session asynchronously, the way the browser requires.
///
/// The connect + handshake cannot block the single browser thread, so it runs off the device
/// handle: the service hands back the connection parameters, the network round-trip happens
/// with `.await`, and the opened session is installed back into the service. A no-op once the
/// session is up.
#[cfg(target_family = "wasm")]
pub(crate) async fn connect_async(&self) {
use crate::client::service::wasm_connect;
let Some(plan) = self
.handle
.submit_blocking(|s| s.wasm_connect_plan())
.expect("Service call failed")
else {
return;View on GitHub (pinned to d16f7ba2ed)
Solutions
- Recreate the client/service connection instead of reusing the stale handle.
- Check the remote server is running and reachable before creating the client.
- Keep the service/runner alive for the lifetime of all handles (don't drop the owner early).
- Inspect server logs for the underlying connection or backend failure.
Example fix
// before let client = RemoteClient::create(&config); drop(runner); // service shut down client.ensure_connected(); // panics: Service call failed // after let client = RemoteClient::create(&config); client.ensure_connected(); // while service is alive // if shutdown happened: create a fresh client instead of reusing
Defensive patterns
Strategy: try-catch
Validate before calling
// check liveness before calling
if client.service_alive() /* or try a cheap submit that tolerates None */ {
client.ensure_connected();
} Try / catch
// wrap the panic boundary so the app can reconnect
let connected = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| client.ensure_connected()));
if connected.is_err() {
let client = RemoteClient::create(&config); // rebuild service and retry
client.ensure_connected();
} Prevention
- Keep the service/runner alive for the lifetime of all handles
- Never use client handles after shutdown/drop of the owning runtime
- Monitor remote server health before issuing device enumeration
- Catch panics at the connection boundary to enable reconnect logic
When it happens
Trigger: Calling `ensure_connected()` (directly or via `RemoteDevice::defaults`/`enumerate`) after the service runner thread has stopped (client dropped/shutdown, panic in the service, or the handle's channel was closed), so `submit_blocking` yields `None`.
Common situations: Using a remote client/handle after the runtime was torn down; server process crashed mid-session; holding a cloned handle past shutdown; environment where the compute server failed to start (bad address, missing backend).
Related errors
- Service call failed
- Can't register manually a tensor on a remote channel.
- Invalid response type for ReadTensor
- capture tensor operations must run inside CaptureDevice::cap
- Capture tensors do not support autodiff
AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05).
Data as JSON: /api/errors/f31ba67b5bf75e46.
Report an issue: GitHub.