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
- Keep the load guard and the expect branch's condition in lockstep — both keyed on !updates.is_empty()
- Replace expect with .ok_or_else(|| format!("index info unavailable for '{}'", index)) so it degrades to an error
- Restructure to load index_info inside the updates branch: `let info = index_info(client, index).await?;` making the expect unnecessary
- 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
- Create indexes with an explicit primary key before document writes
- Check index metadata (GET /indexes/{uid}) before batch updates
- Separate insert-only batches (which skip primary key requirements) from update batches
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
- a batch cancellation token is always available
- driver token registered
- a cancellation token is always available
- checked one driver
- checked one native platform
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/d3e331db04c93a87.
Report an issue: GitHub.