cocoindex-io/cocoindex · critical
with_base_url must be called before the connection is shared
Error message
with_base_url must be called before the connection is shared
What it means
TurboBuffer/ turbopuffer connection objects are shared via Arc; with_base_url() needs exclusive access (&mut via Arc::get_mut) to mutate the base URL. If the connection has already been cloned/shared (refcount > 1), Arc::get_mut returns None and the code panics. The API contract is: configure the URL before sharing the connection.
Source
Thrown at rust/sdk/cocoindex/src/turbopuffer.rs:71
}
fn build(base_url: String, api_key: String, state_id: String) -> Self {
Self {
inner: Arc::new(ConnInner {
http: reqwest::Client::new(),
base_url: base_url.trim_end_matches('/').to_string(),
api_key,
state_id,
}),
}
}
/// Override the base URL (default `https://{region}.turbopuffer.com`). Mainly
/// for pointing at a mock server in tests.
pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
let base_url = base_url.into().trim_end_matches('/').to_string();
let inner = Arc::get_mut(&mut self.inner)
.expect("with_base_url must be called before the connection is shared");
inner.base_url = base_url;
self
}
/// Stable identity for use as a `ContextKey` state id / memo dep.
pub fn state_id(&self) -> &str {
&self.inner.state_id
}
async fn write(&self, namespace: &str, body: JsonValue) -> Result<()> {
let url = format!("{}/v2/namespaces/{namespace}", self.inner.base_url);
self.inner
.http
.post(&url)
.bearer_auth(&self.inner.api_key)
.json(&body)
.send()
.awaitView on GitHub (pinned to e84aa99b32)
Solutions
- Reorder code: call .with_base_url() on the builder/connection before any clone or sharing.
- Rebuild the connection with the desired base_url instead of mutating a shared one.
- In tests, construct a fresh connection per scenario that needs a different base URL.
Example fix
// before let shared = conn.clone(); conn.with_base_url(mock_url()); // panics // after let conn = conn.with_base_url(mock_url()); let shared = conn.clone();
Defensive patterns
Strategy: validation
Validate before calling
// configure before sharing
let conn = TurboConnection::new(region, creds)
.with_base_url("http://localhost:8080");
let shared = std::sync::Arc::new(conn); // share only after config Prevention
- Always finalize configuration (base URL, credentials) before cloning/sharing the connection.
- In tests, build one connection per mock-server scenario instead of retargeting a shared one.
- Treat connection objects as immutable after publication.
When it happens
Trigger: Calling conn.with_base_url("http://localhost:8080") after the connection was cloned, moved into a context/pool, or otherwise shared (Arc strong count > 1). Typical in tests that share one connection across setup code and then try to redirect it to a mock server.
Common situations: Test fixtures that create a connection, register/provide it somewhere, and then attempt to point it at a mock; storing the connection in a struct before finishing configuration.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Environment::provide: type `{}` has already been provided
- Environment::provide_key({}): {e}
- invalid exclude_reference_patterns regex
- valid tokenizer regex
- turbopuffer is required to use the Turbopuffer connector. Pl
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/219f4b697e2b7d98.
Report an issue: GitHub.