Home / AI & GenAI / Vector Databases

AI & GenAITroubleshootingIntermediate

Milvus \"collection not loaded\" errors and query node memory: load, release, replicas and mmap

Searches fail with "collection not loaded" after a restart or deploy, loads hang at 90%, or query nodes run out of memory as collections are added. Understand Milvus load state, size memory for loaded collections, and use release, partitions, replicas and mmap to stay within budget.

Deepak Bhardwaj5 min read

Applies toMilvus 2.4-2.6 standalone and distributed, pymilvus MilvusClient API; Zilliz Cloud handles loading differently

Symptoms

  • search or query fails with an error such as collection not loaded (code 101).
  • After a cluster restart, some collections answer and others don't.
  • load_collection hangs or stays at a progress below 100%.
  • Query nodes are OOMKilled as more collections go live.

Why loading matters

Milvus keeps collection data on object storage. To search a collection, query nodes must load its segments and indexes into memory (or memory-mapped files). A collection that isn't loaded can't be searched. Loaded collections consume query node memory until they're released.

Step 1: check the load state

from pymilvus import MilvusClient

client = MilvusClient(uri="http://milvus:19530", token="root:<password>")

for name in client.list_collections():
    print(name, client.get_load_state(collection_name=name))

States: NotLoad, Loading, Loaded, NotExist. For progress on a slow load, Attu (the Milvus web UI) and the get_loading_progress utility in the ORM API both show percentage.

Step 2: load correctly

client.load_collection(collection_name="kb_chunks")              # waits until loaded by default
client.get_load_state(collection_name="kb_chunks")

A collection must have an index on its vector field before it can be loaded. If it doesn't, the load fails; create the index first.

Make loading part of deployment, not something you hope is already done:

def ensure_loaded(name):
    state = client.get_load_state(collection_name=name)["state"]   # a LoadState enum
    if state.name != "Loaded":
        client.load_collection(collection_name=name)

Run it as a startup step of the application or a post-deploy job.

Step 3: why a load hangs

Cause Evidence Fix
Not enough query node memory Query node memory near limit; load stuck Release other collections, add query nodes, mmap
Index still building client.describe_index shows pending rows / in progress Wait for index build or add index nodes
Object storage slow or unreachable Query node logs show storage errors/timeouts Fix storage (see the dependency post)
Query nodes restarting Pod restarts during load Check OOM and probes
kubectl top pods -n milvus | grep querynode
kubectl logs -n milvus <querynode-pod> | grep -iE "load|memory|oom" | tail -30

Step 4: size memory for loaded collections

Rough memory per loaded collection:

Component Approx. memory
Raw vectors (float32) rows × dims × 4 bytes
HNSW index Raw vectors + graph (rows × M × 2 × ~4–8 bytes)
IVF_FLAT About the raw vector size
IVF_SQ8 / IVF_PQ A fraction of raw vectors
DiskANN Small in memory; most on local NVMe
Scalar fields Depends on types; VARCHAR text fields can be large

Ten million 768-dim vectors are about 30 GB raw; HNSW adds to that. Leave 30%+ headroom for growing segments, query processing and compaction.

Milvus also enforces a memory guard: if a load would push the query node above a configured share of memory (queryNode.overloadedMemoryThresholdPercentage), the load is refused or can't complete. That's protection, not a bug.

Step 5: keep only what you need in memory

Technique How
Release idle collections client.release_collection(collection_name="old_kb")
Load only fields you search/return load_collection(..., load_fields=["id","embedding","doc_id"]) (2.5+; check your version)
Partitions Load only current partitions: client.load_partitions(collection_name=..., partition_names=["2026"])
Don't store big text in Milvus Keep chunk text in another store; keep only IDs and filter fields
Memory-mapped storage Enable mmap so data is paged from local disk instead of held fully in RAM

Enable mmap on a collection (supported versions; release it first, then reload):

client.release_collection(collection_name="kb_chunks")
client.alter_collection_properties(collection_name="kb_chunks", properties={"mmap.enabled": True})
client.load_collection(collection_name="kb_chunks")

mmap trades memory for disk I/O: it needs fast local SSD on query nodes and raises latency if the working set doesn't fit in page cache. Test with real queries.

Step 6: replicas for availability and throughput

client.load_collection(collection_name="kb_chunks", replica_number=2)

Two replicas place two in-memory copies on different query nodes: more search throughput and survival of one query node failure, at twice the memory. You need at least as many query nodes as replicas.

Step 7: after restarts

In current versions Milvus remembers which collections were loaded and reloads them after a restart, but large collections take time to come back. During that window searches fail. Plan for it:

  • Readiness in the application: don't send traffic until get_load_state is Loaded for required collections.
  • Multiple replicas and rolling restarts of query nodes, so one copy stays loaded.

Decision table

Finding Action
NotLoad after deploy Add ensure_loaded to deployment
Load stuck, memory full Release, partition, mmap or more query nodes
Load stuck, index building Wait or scale index nodes
OOM as collections are added Capacity plan per collection; release unused ones
Searches fail during restart Replicas + rolling restarts + readiness

Prevent it next time

  • Keep a capacity sheet: rows, dims, index type and memory per loaded collection.
  • Alert on query node memory above 75%.
  • Release collections that are no longer queried; drop the ones that are retired.
  • Load in a deployment step with a check, never by hand.