{"record":{"id":"d825bec94c4ea872","repo":"clockworklabs/SpacetimeDB","slug":"v2-unsubscribe-requires-binary-protocol","errorCode":null,"errorMessage":"v2 unsubscribe requires binary protocol","messagePattern":"v2 unsubscribe requires binary protocol","errorType":"exception","errorClass":"DBError::Other","httpStatus":null,"severity":"error","filePath":"crates/core/src/subscription/module_subscription_actor.rs","lineNumber":1026,"sourceCode":"        };\n\n        let mut_tx = ScopeGuard::<MutTxId, _>::into_inner(mut_tx);\n        let (mut tx, tx_offset) = self.unsubscribe_views_and_downgrade_tx(mut_tx, &removed_queries, auth.caller())?;\n\n        let (rows, metrics) = if request.flags == ws_v2::UnsubscribeFlags::SendDroppedRows {\n            let (update, metrics) = return_on_err!(\n                self.evaluate_queries(sender.clone(), &removed_queries, &tx, TableUpdateType::Unsubscribe,),\n                send_err_msg,\n                (None, false)\n            );\n            subscription_metrics\n                .num_queries_evaluated\n                .inc_by(removed_queries.len() as _);\n\n            let query_rows = match update {\n                ws_v1::FormatSwitch::Bsatn(update) => query_rows_from_update(update, true)?,\n                ws_v1::FormatSwitch::Json(_) => {\n                    return Err(DBError::Other(anyhow::anyhow!(\n                        \"v2 unsubscribe requires binary protocol\"\n                    )))\n                }\n            };\n            (Some(query_rows), Some(metrics))\n        } else {\n            (None, None)\n        };\n        if let Some(metrics) = metrics {\n            tx.metrics.merge(metrics);\n        }\n\n        let _ = self.broadcast_queue.send_client_message_v2(\n            sender.clone(),\n            Some(tx_offset),\n            ws_v2::UnsubscribeApplied {\n                request_id: request.request_id,\n                query_set_id: request.query_set_id,","sourceCodeStart":1008,"sourceCodeEnd":1044,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/9e0d92412ff2248f401a8ad12d535f2b5ac30912/crates/core/src/subscription/module_subscription_actor.rs#L1008-L1044","documentation":"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.","triggerScenarios":"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.","commonSituations":"Client/server version skew; connecting a v2 client to a server that only produces JSON updates; test harnesses forcing the wrong FormatSwitch.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// On the client, confirm the connection negotiated the v2 binary protocol before\n// requesting dropped rows on unsubscribe\nif request_flags.contains(UnsubscribeFlags::SendDroppedRows) && !connection.negotiated_v2_binary() {\n    // clear the flag or reconnect with the v2 protocol\n}","typeGuard":null,"tryCatchPattern":"match unsubscribe_result {\n    Err(e) if e.to_string().contains(\"v2 unsubscribe requires binary protocol\") => {\n        // Version/format mismatch: reconnect with a matched v2-capable server\n    }\n    other => other,\n}","preventionTips":["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"],"tags":["spacetimedb","subscriptions","unsubscribe","v2-protocol","bsatn"],"backgroundTag":"protocol-format-mismatch","analyzedSha":"9e0d92412ff2248f401a8ad12d535f2b5ac30912","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}