[HNSW] AddMulti panics on nil multivector input
Author: leemeiiCreated Sep 7, 2026Updated Sep 8, 2026
Labelsbugcommunity
How to reproduce this bug?
Save the following file as repro.py in a clean Weaviate source checkout:
#!/usr/bin/env python3
import os
import subprocess
from pathlib import Path
HELPER = r'''
package hnsw
import (
"context"
"fmt"
"testing"
)
func TestAuditNilMultiVector(t *testing.T) {
idx := createEmptyMultiVectorHnswIndexForTests(t, func(context.Context, uint64) ([][]float32, error) {
return nil, nil
})
defer idx.Shutdown(context.Background())
err := idx.AddMulti(context.Background(), 1, nil)
fmt.Printf("target nil_multivector err=%v\n", err)
}
func TestAuditEmptyInnerVector(t *testing.T) {
idx := createEmptyMultiVectorHnswIndexForTests(t, func(context.Context, uint64) ([][]float32, error) {
return nil, nil
})
defer idx.Shutdown(context.Background())
err := idx.AddMulti(context.Background(), 1, [][]float32{{}})
fmt.Printf("control empty_inner_multivector err=%v\n", err)
}
'''
def run(go, source, test_name):
return subprocess.run(
[
go, "test", "./adapters/repos/db/vector/hnsw",
"-run", f"^{test_name}$", "-count=1", "-v",
],
cwd=source,
text=True,
capture_output=True,
timeout=120,
)
def main():
source = Path(os.environ.get("WEAVIATE_SRC", ".")).resolve()
go = os.environ.get("GO_BIN", "go")
helper = source / "adapters/repos/db/vector/hnsw/audit_empty_multivector_test.go"
helper.write_text(HELPER, encoding="utf-8")
try:
passed = True
for trial in range(10):
control = run(go, source, "TestAuditEmptyInnerVector")
target = run(go, source, "TestAuditNilMultiVector")
control_output = control.stdout + control.stderr
target_output = target.stdout + target.stderr
control_ok = (
control.returncode == 0
and "control empty_inner_multivector" in control_output
and "panic:" not in control_output
)
target_ok = (
target.returncode != 0
and "panic:" in target_output
and "runtime error: index out of range [0] with length 0" in target_output
and "AddMultiBatch.func2" in target_output
and "insert.go:316" in target_output
)
ok = control_ok and target_ok
passed &= ok
print(
f"trial={trial + 1} "
f"control={control.returncode} "
f"target={target.returncode} "
f"oracle={ok}"
)
print(
"BUG REPRODUCED: nil multivector causes HNSW AddMulti panic"
if passed else
"NO BUG OBSERVED OR INCONCLUSIVE"
)
return 0 if passed else 10
finally:
helper.unlink(missing_ok=True)
if __name__ == "__main__":
raise SystemExit(main())
### What is the expected behavior?
A nil or empty multivector is invalid input, but `AddMulti` should return a controlled error instead of panicking.
Expected behavior:- return an error;
- do not access a missing inner vector;
- keep the Go process alive;
- leave the HNSW index state unchanged.
The adjacent input `[][]float32{{}}` already returns a controlled error without panicking.
### What is the actual behavior?
Calling:
```go
idx.AddMulti(context.Background(), 1, nil)terminates the test process with:
panic: runtime error: index out of range [0] with length 0The stack trace reaches:
AddMultiBatch.func2
adapters/repos/db/vector/hnsw/insert.go:316The process exits with a non-zero status instead of returning an error.
Supporting information
No response
Server Version
1.40.0-dev
Weaviate Setup
Single Node
Nodes count
No response
Code of Conduct
- I have read and agree to the Weaviate's Contributor Guide and Code of Conduct
Source: weaviate/weaviate