tracel-ai/burn · critical
Invalid response type for ReadTensor
Error message
Invalid response type for ReadTensor
What it means
In burn-remote, `read_tensor_async` submits a tensor-read request to the remote service and awaits a response on a oneshot channel. The protocol contract is that the reply carries `TaskResponseContent::ReadTensor`; if the server/channel delivers any other task-response variant, the client panics with this message. It indicates a client/server protocol desynchronization or a mismatched response routing, not a tensor data error (genuine transport failures come back as `ExecutionError::Generic` on the Err branch).
Source
Thrown at crates/burn-remote/src/client/runner.rs:47
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();
// Fire-and-forget: the outgoing batch flushes itself once buffered data bytes (or the task
// count) cross their threshold — see `OutgoingBatch` — so no explicit flush is needed here.
let stream_id = StreamId::current();
self.handle
.submit(move |s| s.register_tensor(stream_id, id, data));View on GitHub (pinned to d16f7ba2ed)
Solutions
- Rebuild and redeploy client and server from the same burn version so the TaskResponseContent wire protocol matches.
- Verify no custom/forked service code routes responses to the wrong stream id for read_tensor requests.
- Update to the latest burn release; if it persists, file a bug with a minimal repro (remote backend, read a tensor after a couple of ops).
Example fix
// before: client 0.x talking to server 0.y (protocol skew) -> panic
// after: pin the same burn version on both sides
# Cargo.toml (client and server)
[dependencies]
burn = { version = "=0.18.0", features = ["remote"] } Defensive patterns
Strategy: try-catch
Validate before calling
// ensure client and server report the same burn version before exchanging tensors assert_eq!(client.protocol_version(), server.protocol_version());
Type guard
match response {
TaskResponseContent::ReadTensor(res) => Ok(res),
other => Err(format!("unexpected response variant: {other:?}")),
} Try / catch
// panic! cannot be caught in stable Rust without catch_unwind
let result = std::panic::catch_unwind(AssertUnwindSafe(|| tensor.into_data()));
match result {
Ok(data) => { /* use data */ }
Err(_) => { /* reconnect with matching versions */ }
} Prevention
- Pin identical burn versions in client and server Cargo.tomls
- Add a version/handshake check when opening the remote connection
- Avoid custom forks of the remote service protocol
When it happens
Trigger: Calling `.into_data()`/`to_data()` (which routes through RouterClient::read_tensor_async) on a tensor owned by a RemoteClient when the oneshot `rx` resolves with a TaskResponseContent variant other than ReadTensor — i.e. the response queued for this stream id belongs to a different task.
Common situations: Client/server version skew where response variants were reordered or remapped between burn versions; running mismatched burn-remote client and server binaries; stream id reuse/collision after sync; custom or forked server code replying with the wrong TaskResponseContent.
Related errors
- Can't register manually a tensor on a remote channel.
- Service call failed
- Service call failed
- 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/bfe8113a5bd12aec.
Report an issue: GitHub.