tracel-ai/burn · error

Service call failed

Error message

Service call failed

What it means

`read_tensor_async` synchronously submits a `read_tensor` request via `handle.submit_blocking(...)` and unwraps the returned oneshot receiver with `expect("Service call failed")`. If the submission cannot reach the service (runner shut down, channel closed) the call returns `None` and panics. Note the subsequent `rx.await` handles real execution errors as `ExecutionError` — this expect only fires for local service-channel failure.

Source

Thrown at crates/burn-remote/src/client/runner.rs:42

        let stream_id = StreamId::current();
        // Device ids in the op's payload are *client* remote device ids; rewrite them to
        // server-local device indices the server can resolve to its own backend devices. Applies
        // to every op — only ops that actually carry device ids are rewritten.
        let op = self.resolve_devices(op);
        self.handle.submit(move |s| s.register_op(stream_id, op));
    }

    fn read_tensor_async(
        &self,
        tensor: burn_ir::TensorIr,
    ) -> DynFut<Result<TensorData, ExecutionError>> {
        // Issue the request synchronously so ordering is preserved relative to subsequent
        // submissions; the returned future just awaits the server's response.
        let stream_id = StreamId::current();
        let rx = self
            .handle
            .submit_blocking(move |s| s.read_tensor(stream_id, tensor))
            .expect("Service call failed");

        Box::pin(async move {
            match rx.await {
                Ok(TaskResponseContent::ReadTensor(res)) => res,
                Ok(_) => panic!("Invalid response type for ReadTensor"),
                Err(e) => Err(ExecutionError::Generic {
                    reason: format!("Failed to read tensor: {e:?}"),
                    backtrace: BackTrace::capture(),
                }),
            }
        })
    }

    fn register_tensor_data(&self, data: TensorData) -> RouterTensor<Self> {
        let shape = data.shape.clone();
        let dtype = data.dtype;
        let id = service::new_tensor_id();

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Recreate the remote client/backend after the service dies, then re-issue the read.
  2. Keep the service/runner alive until all in-flight tensor reads complete.
  3. Use `sync`/connection health checks before reads in long-running sessions.
  4. Catch the panic at a boundary (e.g. `catch_unwind`) if shutdown races are unavoidable, and reconnect.

Example fix

// before
let tensor = backend.read_tensor(desc).await; // panics if service dead
// after
// ensure client is alive or recreate:
let backend = get_or_recreate_backend(&config);
let tensor = backend.read_tensor(desc).await;
Defensive patterns

Strategy: try-catch

Validate before calling

// guard long sessions: verify connectivity before reads
// e.g. issue a cheap sync/heartbeat; on failure recreate the backend
if !backend_healthy(&handle) { let backend = recreate_backend(&config)?; }

Try / catch

let tensor = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    backend_clone.read_tensor(desc)
}));
if tensor.is_err() { /* recreate backend, re-issue read */ }

Prevention

When it happens

Trigger: Calling tensor read (via the async backend's `read_tensor`) after the remote service runner has terminated, or submitting on a handle whose channel is closed, so `submit_blocking` returns `None` instead of a response receiver.

Common situations: Reading results after the remote server crashed or connection was torn down; using a client/handle beyond shutdown; WASM suspension killing the service; holding cloned backend past client drop.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/046a9e92b8ad0390. Report an issue: GitHub.