zeroclaw-labs/zeroclaw · error

Qdrant requires non-zero dimensional embeddings

Error message

Qdrant requires non-zero dimensional embeddings

What it means

store_with_agent() embeds "<key>\n<content>" via embed_one() and requires a non-empty vector because a Qdrant point must carry a vector. If the installed embedder is the no-op provider (dimensions() == 0, empty Vec output), every store fails with this error before any HTTP call. Scroll-based reads (get/list) keep working, which makes it look like a partial outage.

Source

Thrown at crates/zeroclaw-memory/src/qdrant.rs:935

    }

    async fn store_with_agent(
        &self,
        key: &str,
        content: &str,
        category: MemoryCategory,
        session_id: Option<&str>,
        _namespace: Option<&str>,
        _importance: Option<f64>,
        agent_id: Option<&str>,
    ) -> Result<()> {
        self.ensure_initialized().await?;

        let combined_text = format!("{}\n{}", key, content);
        let embedder = self.embedder.read().clone();
        let embedding = embedder.embed_one(&combined_text).await?;
        if embedding.is_empty() {
            anyhow::bail!("Qdrant requires non-zero dimensional embeddings");
        }

        let id = Uuid::new_v4().to_string();
        let timestamp = Utc::now().to_rfc3339();

        let resolved_agent_id = agent_id.unwrap_or("default").to_string();
        let payload = MemoryPayload {
            key: key.to_string(),
            content: content.to_string(),
            category: Self::category_to_str(&category),
            timestamp,
            session_id: session_id.map(str::to_string),
            agent_id: Some(resolved_agent_id.clone()),
        };

        self.delete_points_matching(&[("key", key), ("agent_id", resolved_agent_id.as_str())])
            .await
            .context("qdrant pre-upsert cleanup failed")?;

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Configure a real embedding provider for memory (model_provider with an embedding-capable profile) and restart
  2. If you don't want embeddings, switch the backend to sqlite (brain.db), which stores and searches without vectors
  3. After a config/set provider change, confirm QdrantMemory::embedder_dimensions() > 0 before writing
  4. Guard store call sites: skip or queue writes while dimensions are 0

Example fix

# before
[memory]
backend = "qdrant"        # no model_provider -> Noop embedder; all stores fail

# after
[memory]
backend = "qdrant"
model_provider = "openai"  # real embedder; stores now carry vectors
Defensive patterns

Strategy: validation

Validate before calling

// With the concrete QdrantMemory handle (before any store):
if qdrant_memory.embedder_dimensions() == 0 {
    anyhow::bail!("configure an embedding provider before storing to the qdrant backend");
}

Try / catch

match memory.store(key, content).await {
    Err(e) if e.to_string().starts_with("Qdrant requires non-zero dimensional embeddings") => {
        surface_config_error("memory backend needs model_provider with embeddings"); Ok(())
    }
    other => other,
}

Prevention

When it happens

Trigger: Backend set to qdrant while the memory factory installed the Noop embedder (no embedding provider configured); the embedder was hot-swapped to a provider that returns empty vectors.

Common situations: Choosing the qdrant backend for semantic search without configuring model_provider; local setups without an API key for an embedding API; assuming qdrant stores raw text like the sqlite backend.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/dfa71a95205fe155. Report an issue: GitHub.