What
ComposioConnectionsResponse is an untagged enum with a #[serde(default)] on the object variant's connections field:
#[serde(untagged)]
pub enum ComposioConnectionsResponse {
List(Vec<ComposioConnection>),
Object {
#[serde(default)]
connections: Vec<ComposioConnection>,
},
}
Untagged matching tries List first; any JSON object fails that and falls through to Object, where the default means a missing connections key deserializes to an empty vector instead of erroring. So if the backend ever renames the key or changes the wrapper shape, list_composio_connections returns Ok with zero connections rather than failing — a wire-format change reads to callers as "this user has no integrations connected."
Raised by CodeRabbit on #16 (#16 (comment)). Filed separately because #16 is a verified pure file move and fixing it there would have broken that guarantee.
What is not affected
The related scenario CodeRabbit raised — an error-shaped object returned with HTTP 200 — is already handled upstream of deserialization. unwrap_envelope in src/lib.rs turns {success: false, ...} into Error::Envelope before any typed decoding runs, so that path already fails loudly.
The exposure is narrower: a successful envelope whose data object doesn't carry connections.
Suggested fix
Drop the #[serde(default)] so the object variant requires the key:
Object { connections: Vec<ComposioConnection> },
A shape the SDK doesn't recognize then fails as a decode error, which is the honest outcome.
Worth confirming against the deployed backend first that no live response relies on the object variant with connections absent — the doc comment notes the backend has emitted both a bare array and { connections: [...] }, and the default may have been added to paper over a third shape observed in the wild. If so, that third shape should get its own variant rather than being silently flattened to empty.
Acceptance
- The object variant requires
connections.
- A round-trip test covers the bare-array shape, the
{connections: [...]} shape, and an unrecognized object shape erroring rather than returning empty.
What
ComposioConnectionsResponseis an untagged enum with a#[serde(default)]on the object variant'sconnectionsfield:Untagged matching tries
Listfirst; any JSON object fails that and falls through toObject, where thedefaultmeans a missingconnectionskey deserializes to an empty vector instead of erroring. So if the backend ever renames the key or changes the wrapper shape,list_composio_connectionsreturnsOkwith zero connections rather than failing — a wire-format change reads to callers as "this user has no integrations connected."Raised by CodeRabbit on #16 (#16 (comment)). Filed separately because #16 is a verified pure file move and fixing it there would have broken that guarantee.
What is not affected
The related scenario CodeRabbit raised — an error-shaped object returned with HTTP 200 — is already handled upstream of deserialization.
unwrap_envelopeinsrc/lib.rsturns{success: false, ...}intoError::Envelopebefore any typed decoding runs, so that path already fails loudly.The exposure is narrower: a successful envelope whose data object doesn't carry
connections.Suggested fix
Drop the
#[serde(default)]so the object variant requires the key:A shape the SDK doesn't recognize then fails as a decode error, which is the honest outcome.
Worth confirming against the deployed backend first that no live response relies on the object variant with
connectionsabsent — the doc comment notes the backend has emitted both a bare array and{ connections: [...] }, and thedefaultmay have been added to paper over a third shape observed in the wild. If so, that third shape should get its own variant rather than being silently flattened to empty.Acceptance
connections.{connections: [...]}shape, and an unrecognized object shape erroring rather than returning empty.