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()
            .await

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Reorder code: call .with_base_url() on the builder/connection before any clone or sharing.
  2. Rebuild the connection with the desired base_url instead of mutating a shared one.
  3. 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

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


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/219f4b697e2b7d98. Report an issue: GitHub.