clockworklabs/SpacetimeDB · error · DBError::Other
v2 unsubscribe requires binary protocol
Error message
v2 unsubscribe requires binary protocol
What it means
The v2 unsubscribe path with UnsubscribeFlags::SendDroppedRows must evaluate the removed queries and return their rows in the v2 binary format. evaluate_queries returned FormatSwitch::Json, meaning subscription evaluation ran under the JSON format while the client negotiated v2 BSATN. The v2 QueryRows structure cannot be built from JSON updates, so the unsubscribe fails.
Source
Thrown at crates/core/src/subscription/module_subscription_actor.rs:1026
};
let mut_tx = ScopeGuard::<MutTxId, _>::into_inner(mut_tx);
let (mut tx, tx_offset) = self.unsubscribe_views_and_downgrade_tx(mut_tx, &removed_queries, auth.caller())?;
let (rows, metrics) = if request.flags == ws_v2::UnsubscribeFlags::SendDroppedRows {
let (update, metrics) = return_on_err!(
self.evaluate_queries(sender.clone(), &removed_queries, &tx, TableUpdateType::Unsubscribe,),
send_err_msg,
(None, false)
);
subscription_metrics
.num_queries_evaluated
.inc_by(removed_queries.len() as _);
let query_rows = match update {
ws_v1::FormatSwitch::Bsatn(update) => query_rows_from_update(update, true)?,
ws_v1::FormatSwitch::Json(_) => {
return Err(DBError::Other(anyhow::anyhow!(
"v2 unsubscribe requires binary protocol"
)))
}
};
(Some(query_rows), Some(metrics))
} else {
(None, None)
};
if let Some(metrics) = metrics {
tx.metrics.merge(metrics);
}
let _ = self.broadcast_queue.send_client_message_v2(
sender.clone(),
Some(tx_offset),
ws_v2::UnsubscribeApplied {
request_id: request.request_id,
query_set_id: request.query_set_id,View on GitHub (pinned to 9e0d92412f)
Solutions
- Upgrade client and server to matching versions that both support the v2 binary protocol
- Ensure the connection negotiates the v2 protocol end-to-end so evaluation uses BSATN
- For custom builds, verify the subscription actor is configured for BSATN, not JSON, on v2 connections
Defensive patterns
Strategy: validation
Validate before calling
// On the client, confirm the connection negotiated the v2 binary protocol before
// requesting dropped rows on unsubscribe
if request_flags.contains(UnsubscribeFlags::SendDroppedRows) && !connection.negotiated_v2_binary() {
// clear the flag or reconnect with the v2 protocol
} Try / catch
match unsubscribe_result {
Err(e) if e.to_string().contains("v2 unsubscribe requires binary protocol") => {
// Version/format mismatch: reconnect with a matched v2-capable server
}
other => other,
} Prevention
- Use matching client and server versions
- Prefer the v2 binary protocol consistently for clients that need v2 features
- Gate v2-only flags on protocol negotiation in client SDKs
When it happens
Trigger: A v2 (binary protocol) client sending Unsubscribe with SendDroppedRows when the subscription actor evaluates queries with the JSON format - a format mismatch between negotiated protocol version and evaluation settings.
Common situations: Client/server version skew; connecting a v2 client to a server that only produces JSON updates; test harnesses forcing the wrong FormatSwitch.
Related errors
- v2 subscriptions require binary protocol
- unexpected compressed v1 update for v2 subscribe
- Index '${indexLabel}' on table '${tableLabel}' must define a
- Argument must be a I128
- Argument must be a I256
AI-assisted analysis of clockworklabs/SpacetimeDB@9e0d92412f (2026-08-20).
Data as JSON: /api/errors/d825bec94c4ea872.
Report an issue: GitHub.