t8y2/dbx · error

index info is loaded for document writes

Error message

index info is loaded for document writes

What it means

Panic from `Option::expect` on the cached `index_info` in save_document_batch. The code loads index metadata whenever there are updates or inserts, then asserts it is Some inside the updates branch — which only runs when updates is non-empty, so the load already happened. A panic indicates the load condition and the branch condition drifted apart (a refactor bug), or index_info(client, index) returned but the Some(...) wrapper was bypassed; note that an actual metadata fetch failure already propagates via `?` above.

Source

Thrown at crates/dbx-core/src/db/meilisearch_driver.rs:594

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MeilisearchDocumentUpdate {
    pub id: String,
    pub doc_json: String,
}

pub async fn save_document_batch(
    client: &MeilisearchClient,
    index: &str,
    updates: &[MeilisearchDocumentUpdate],
    delete_ids: &[String],
    inserts: &[String],
) -> Result<u64, String> {
    let index_info =
        if updates.is_empty() && inserts.is_empty() { None } else { Some(index_info(client, index).await?) };

    if !updates.is_empty() {
        let index_info = index_info.as_ref().expect("index info is loaded for document writes");
        let primary_key = index_info
            .primary_key
            .as_deref()
            .ok_or_else(|| format!("Meilisearch index '{}' has no primary key", index_info.uid))?;
        let documents = updates
            .iter()
            .map(|update| {
                let mut document = parse_document_object(&update.doc_json)?;
                document.remove("_id");
                document.insert(primary_key.to_string(), decoded_identity(&update.id));
                Ok(Value::Object(document))
            })
            .collect::<Result<Vec<_>, String>>()?;
        submit_documents(client, index, Method::POST, documents).await?;
    }

    if !delete_ids.is_empty() {
        let ids = delete_ids.iter().map(|id| decoded_identity(id)).collect::<Vec<_>>();

View on GitHub (pinned to c0390bff16)

Solutions

  1. Keep the load guard and the expect branch's condition in lockstep — both keyed on !updates.is_empty()
  2. Replace expect with .ok_or_else(|| format!("index info unavailable for '{}'", index)) so it degrades to an error
  3. Restructure to load index_info inside the updates branch: `let info = index_info(client, index).await?;` making the expect unnecessary
  4. Add a test for update-only, insert-only, and empty batches to pin the loading behavior

Example fix

// before
let index_info = index_info.as_ref().expect("index info is loaded for document writes");
// after
let index_info = index_info.as_ref()
    .ok_or_else(|| format!("Meilisearch index info unavailable for '{}' during document writes", index))?;
Defensive patterns

Strategy: try-catch

Validate before calling

let idx = client.get_index(&index).await?;
if idx.primary_key.is_none() {
    return Err(format!("Meilisearch index '{}' has no primary key; set one before updates", index));
}

Type guard

fn index_supports_updates(info: &IndexInfo) -> bool {
    info.primary_key.as_deref().map(|k| !k.is_empty()).unwrap_or(false)
}

Try / catch

match save_document_batch(client, index, &updates, &inserts).await {
    Ok(count) => count,
    Err(e) if e.contains("no primary key") => configure_primary_key_then_retry(),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Executing save_document_batch with non-empty updates where index_info ended up None — only possible if the earlier `if updates.is_empty() && inserts.is_empty()` load guard is changed without updating this branch, or index_info is replaced by a fallible source returning Option differently.

Common situations: Refactors altering the conditional metadata load; restructuring the batch method and dropping the Some(index_info(...)) binding; not reachable from Meilisearch server state (missing primary key has its own explicit error below).

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/d3e331db04c93a87. Report an issue: GitHub.