Weaviate на сервере: частые ошибки и решения
Weaviate ломается предсказуемо: клиент падает на gRPC, хотя REST отвечает; батч отрабатывает без единого исключения, а объектов в коллекции ноль; поиск возвращает пустоту при полной базе. Почти все ошибки Weaviate сводятся к пяти причинам — неопубликованный порт 50051, анонимный доступ, автосхема с чужими типами, забытый тенант и заполненный диск. Разбираем по симптомам.
Содержание
- Три проверки, которые сужают поиск за минуту
- Контейнер не стартует или уходит в бесконечный рестарт
- WeaviateGRPCUnavailableError: клиент не видит gRPC
- 401 и 403: анонимный доступ, API-ключи и RBAC
- Схема и вставка: автосхема, типы и молчаливые батчи
- Поиск ничего не находит, а запись упирается в read-only
- Какой сервер под Weaviate взять в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Три проверки, которые сужают поиск за минуту
«Weaviate не работает» — это три разные поломки: процесс не поднялся, процесс жив и отвечает 4xx, или отвечает 200 не тем. Различаются за минуту.
curl -s http://127.0.0.1:8080/v1/meta | jq '{version, modules: (.modules | keys)}'
curl -s -o /dev/null -w 'live=%{http_code}\n' http://127.0.0.1:8080/v1/.well-known/live
curl -s -o /dev/null -w 'ready=%{http_code}\n' http://127.0.0.1:8080/v1/.well-known/ready
ss -tulpn | grep -E ':(8080|50051)\b'
/v1/meta отдаёт версию и модули — видно, тот ли образ запущен и есть ли нужный векторизатор. /v1/.well-known/ready даёт 503, пока шарды поднимаются после рестарта, — это нормальный старт, не зависание.
Деталь, на которой теряют часы: зелёный ready ничего не говорит про gRPC — REST на 8080, gRPC на отдельном 50051, клиент v4 ходит в оба. Только 8080 в выводе ss — сразу в третью секцию. Дальше — уровень узла и шардов:
curl -s 'http://127.0.0.1:8080/v1/nodes?output=verbose' \
-H "Authorization: Bearer $WEAVIATE_API_KEY" \
| jq '.nodes[] | {name, status, version, shards: [.shards[] | {name, class, objectCount, vectorIndexingStatus}]}'
{
"name": "node1",
"status": "HEALTHY",
"version": "1.34.0",
"shards": [
{"name": "3nKqUn0pXqTz", "class": "Document", "objectCount": 128400, "vectorIndexingStatus": "READY"}
]
}
objectCount нулевой — данные не доехали, в пятую секцию. vectorIndexingStatus: INDEXING — HNSW ещё строится, выдача неполна, это нормально после заливки. Объекты есть, индекс READY, результат пустой — шестая секция.
| Симптом | Где искать причину |
|---|---|
/v1/meta не отвечает | секция 2: порт, том, память |
WeaviateGRPCUnavailableError | секция 3: транспорт клиента |
401 anonymous access not enabled | секция 4: аутентификация |
not a string, but json.Number | секция 5: схема и вставка |
| 200 и пустой результат | секция 6: векторизация, тенант |
store is read-only | секция 6: диск |
Контейнер не стартует или уходит в бесконечный рестарт
Портов Weaviate занимает больше, чем кажется: 8080 — REST и GraphQL, 50051 — gRPC, 7100 — gossip между узлами, 7101 — обмен данными кластера, 8300 и 8301 — Raft, в котором с версии 1.25 живёт схема. О конфликте сообщает Docker, а не Weaviate:
Error response from daemon: driver failed programming external connectivity on
endpoint weaviate: Bind for 0.0.0.0:8080 failed: port is already allocated
Легко нарушить руками: CLUSTER_DATA_BIND_PORT обязан равняться CLUSTER_GOSSIP_BIND_PORT + 1 — поставили 7100 и 7105, узел не соберётся, а в логе будет ругань на bind, а не понятное «неверные порты».
Второй барьер — хранилище: без тома контейнер держит данные в своём слое, и первый docker rm уносит коллекции (docker inspect -f '{{json .Mounts}}' weaviate | jq). При bind-монтировании от root — permission denied на /var/lib/weaviate; именованный том это снимает.
services:
weaviate:
image: cr.weaviate.io/semitechnologies/weaviate:1.34.0
restart: unless-stopped
command: ["--host", "0.0.0.0", "--port", "8080", "--scheme", "http"]
ports:
- "127.0.0.1:8080:8080"
- "127.0.0.1:50051:50051"
volumes:
- weaviate_data:/var/lib/weaviate
- weaviate_backups:/var/lib/weaviate-backups
environment:
PERSISTENCE_DATA_PATH: /var/lib/weaviate
CLUSTER_HOSTNAME: node1
AUTOSCHEMA_ENABLED: 'false'
DEFAULT_VECTORIZER_MODULE: none
ENABLE_MODULES: 'text2vec-ollama,generative-ollama,backup-filesystem'
BACKUP_FILESYSTEM_PATH: /var/lib/weaviate-backups
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false'
AUTHENTICATION_APIKEY_ENABLED: 'true'
AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'ЗАМЕНИТЕ_МЕНЯ'
AUTHENTICATION_APIKEY_USERS: 'admin@example.com'
AUTHORIZATION_ADMINLIST_ENABLED: 'true'
AUTHORIZATION_ADMINLIST_USERS: 'admin@example.com'
QUERY_DEFAULTS_LIMIT: 25
DISK_USE_WARNING_PERCENTAGE: 80
DISK_USE_READONLY_PERCENTAGE: 90
LIMIT_RESOURCES: 'true'
GOMEMLIMIT: 6GiB
DISABLE_TELEMETRY: 'true'
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
weaviate_data:
weaviate_backups:
Третий барьер — CLUSTER_HOSTNAME: менять его после создания узла нельзя (идентичность в состоянии Raft) — переименование контейнера вместо старта даёт жалобы Raft на bootstrap. Честно: откат ниже 1.25 не поддерживается, схема мигрирует в одну сторону.
Четвёртый случай — контейнер, который «сам перезапускается». Обычно его убило ядро:
docker inspect -f '{{.State.ExitCode}} OOMKilled={{.State.OOMKilled}}' weaviate
dmesg -T | grep -i 'killed process'
Код выхода 137 и Out of memory: Killed process — не баг, а нехватка RAM: Weaviate на Go держит граф HNSW в памяти целиком. LIMIT_RESOURCES: 'true' ограничивает ~80% доступной памяти, GOMEMLIMIT задаёт предел вручную — ставьте ниже лимита контейнера. Подробнее — что делать при нехватке RAM.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверWeaviateGRPCUnavailableError: клиент не видит gRPC
Самая частая ошибка у тех, кто пришёл с питоновским клиентом:
weaviate.exceptions.WeaviateGRPCUnavailableError: Weaviate makes use of a high-speed
gRPC API as well as a REST API. Unfortunately, the gRPC health check against Weaviate
could not be completed.
This error could be due to one of several reasons:
- The gRPC traffic at the specified port is blocked by a firewall.
- gRPC is not enabled or incorrectly configured on the server or the client.
REST клиент v4 использует только для схемы, поиск и батч гонит по gRPC. Причин четыре:
- Порт 50051 не опубликован — классика
docker run -p 8080:8080без второго-p. Внутри контейнера gRPC работает, снаружи его нет. - Фаервол.
ufw allow 8080/tcpбез парного правила даёт ровно эту картину: REST отвечает, клиент падает. - Nginx проксирует только REST. Через
proxy_passgRPC не ходит, нуженgrpc_passи HTTP/2. - Мал таймаут инициализации — на медленном канале health-check не успевает.
Оба протокола разводятся одним server-блоком: gRPC-методы живут в сервисе weaviate.v1.Weaviate.
server {
listen 443 ssl;
http2 on;
server_name weaviate.example.com;
location /weaviate.v1.Weaviate/ {
grpc_pass grpc://127.0.0.1:50051;
grpc_read_timeout 600s;
grpc_send_timeout 600s;
}
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
client_max_body_size 64m;
}
}
Директива http2 on; — с Nginx 1.25.1, на старых сборках listen 443 ssl http2;. Без HTTP/2 клиент получит обрыв потока вместо ответа.
import weaviate
from weaviate.classes.init import Auth, AdditionalConfig, Timeout
with weaviate.connect_to_local(
host="127.0.0.1", port=8080, grpc_port=50051,
auth_credentials=Auth.api_key("ЗАМЕНИТЕ_МЕНЯ"),
additional_config=AdditionalConfig(timeout=Timeout(init=30, query=60, insert=180)),
) as client:
print(client.is_ready())
За Nginx берут connect_to_custom с http_port=443, http_secure=True, grpc_port=443, grpc_secure=True. skip_init_checks=True уберёт исключение при подключении, но не транспорт: батч всё равно упадёт на отправке. Проверка gRPC без питона:
grpcurl -plaintext 127.0.0.1:50051 list
# grpc.health.v1.Health
# weaviate.v1.Weaviate
Старый код: weaviate.Client(url=...) теперь даёт AttributeError: module 'weaviate' has no attribute 'Client' — вместо него connect_to_local и client.collections.get("Document").
401 и 403: анонимный доступ, API-ключи и RBAC
Скажем прямо: в стандартной сборке Weaviate аутентификации нет. Конфигуратор генерирует AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true' — любой, кто дотянулся до 8080, читает документы и может выполнить DELETE /v1/schema/Document. Открытый порт находят сканерами за часы.
Защита включается тремя группами переменных — и здесь три ловушки подряд.
- Ключи и пользователи — списки попарно.
AUTHENTICATION_APIKEY_ALLOWED_KEYSиAUTHENTICATION_APIKEY_USERSчерез запятую: либо длины совпадают, либо один пользователь на все ключи. - Включение ключей не выключает анонимку. Пока
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLEDне'false', ключи работают, но и без ключа пускают. - Владелец ключа должен попасть в список прав. Если пользователя нет ни в
AUTHORIZATION_ADMINLIST_USERS, ни вAUTHORIZATION_ADMINLIST_READONLY_USERS, каждый запрос вернёт 403.
Без ключа при выключенной анонимке ответ такой:
UnexpectedStatusCodeError: Meta endpoint! Unexpected status code: 401,
with response body: {'error': [{'message': 'anonymous access not enabled'}]}
Засада для переезжающих с Qdrant: Weaviate принимает ключ только заголовком Authorization: Bearer — привычные api-key и X-API-Key игнорирует, и приходит тот же 401, будто ключа нет вовсе.
curl -s http://127.0.0.1:8080/v1/schema -H "api-key: $WEAVIATE_API_KEY" # 401
curl -s http://127.0.0.1:8080/v1/schema -H "Authorization: Bearer $WEAVIATE_API_KEY"
С версии 1.29 доступна ролевая модель (AUTHORIZATION_RBAC_ENABLED), но для одиночного сервера хватает admin-list: ключ на запись и read-only для приложения, которое только ищет.
Сетевой минимум: публикация на loopback, ufw allow 22/tcp, ufw deny 8080/tcp, ufw deny 50051/tcp, наружу — только Nginx с TLS. И не вешайте auth_basic на тот же location: заголовок Authorization тот же, что и у ключа клиента.
Схема и вставка: автосхема, типы и молчаливые батчи
Самая обидная категория — когда всё «прошло успешно», а данных нет.
Имена классов Weaviate поднимает в верхний регистр. Создали document — в схеме будет Document, и приложение, идущее к document, получит «коллекция не найдена». id и _additional — зарезервированные имена ('id' is a reserved property name), идентификатор передаётся полем uuid.
Автосхема угадывает типы по первому объекту. AUTOSCHEMA_ENABLED включена по умолчанию: первая партия несла "price": "1200" строкой, во второй прилетело число — партия падает.
invalid object: invalid text property 'price' on class 'Product': not a string, but json.Number
Обратная ситуация симметрична, а на пустом массиве тип не определить вовсе. Существующее свойство изменить нельзя — только пересоздать коллекцию; поэтому в продакшене автосхему выключают и описывают свойства явно (новые добавлять это не мешает).
Батчи в клиенте v4 не бросают исключений. Ловушка номер один по числу потерянных вечеров: цикл отработал, ошибок нет, objectCount нулевой. Ошибки смотрят руками:
docs = client.collections.get("Document")
with docs.batch.fixed_size(batch_size=200, concurrent_requests=2) as batch:
for chunk in chunks:
batch.add_object(
properties={"text": chunk["text"], "source": chunk["source"]},
uuid=weaviate.util.generate_uuid5(chunk["source"] + str(chunk["n"])),
vector=chunk["vector"],
)
if batch.number_errors > 10:
break
failed = docs.batch.failed_objects
print(f"не вставлено: {len(failed)}")
if failed:
print(failed[0].message)
Рецепт от дублей: без uuid Weaviate сгенерирует его случайно, переиндексация создаст вторую копию вместо обновления. generate_uuid5 от естественного ключа детерминирован — тот же путь и номер дадут тот же id, перезаливка перезапишет объект.
Размер батча важен: gRPC-сообщение клиент ограничивает ~100 МиБ, десятки тысяч объектов с векторами по 1024 измерения одним куском не влезут — рабочий диапазон 100–500 объектов.
Мультитенантность. Коллекция с multi_tenancy_config требует тенанта в каждом запросе:
collection Document has multi-tenancy enabled, but request was without tenant
Лечится docs.with_tenant("acme") вместо голого docs. Второй вариант той же беды — тенант есть, но неактивен: данные на месте, обращение отклоняется.
Поиск ничего не находит, а запись упирается в read-only
Векторизатора нет. В compose выше стоит DEFAULT_VECTORIZER_MODULE: none — эмбеддинги считаются снаружи, и near_text работать не будет:
explorer: get class: vectorize search vector: no vectorizer found for class Document
Векторизатор должен быть в ENABLE_MODULES и назначен коллекции: невключённый даёт no module with name "text2vec-ollama" present, реальный список — curl -s http://127.0.0.1:8080/v1/meta | jq '.modules | keys'. С локальным text2vec-ollama частый случай — Ollama слушает только 127.0.0.1, без OLLAMA_HOST=0.0.0.0:11434 из контейнера будет connection refused; подробнее — как считать эмбеддинги на CPU без GPU.
Размерность не совпала. Сменили модель и заливаете в старую коллекцию:
new node has a vector with length 1024. Existing nodes have vectors with length 768
Размерность фиксируется первым вектором и не меняется — путь один: новая коллекция и переиндексация.
Фильтр по несуществующему свойству — хорошая новость, ошибка внятная:
no such prop with name 'catgeory' found in class 'Document' in the schema
Хуже, когда свойство есть, а подходящих значений нет — пустой список: снимайте по одному фильтр, порог distance/certainty, поднимайте limit (QUERY_DEFAULTS_LIMIT = 25 по умолчанию). За QUERY_MAXIMUM_RESULTS (10000) коллекцию выгружают курсором, а не растущим offset — иначе query maximum results exceeded.
Диск — фирменное поведение: на 80% предупреждение в логе, на 90% шарды уходят в read-only, клиент получает {"error":[{"message":"store is read-only"}]}. Освободить место мало — статус шарда возвращают руками.
curl -s http://127.0.0.1:8080/v1/schema/Document/shards \
-H "Authorization: Bearer $WEAVIATE_API_KEY" | jq
curl -s -X PUT -H 'Content-Type: application/json' \
-H "Authorization: Bearer $WEAVIATE_API_KEY" \
-d '{"status":"READY"}' \
http://127.0.0.1:8080/v1/schema/Document/shards/3nKqUn0pXqTz
Бэкап — не «скопировать /var/lib/weaviate на живом сервере» (LSM как раз компактится): штатный путь — модуль backup-filesystem, включённый заранее.
curl -s -X POST http://127.0.0.1:8080/v1/backups/filesystem \
-H 'Content-Type: application/json' -H "Authorization: Bearer $WEAVIATE_API_KEY" \
-d '{"id":"backup-2026-08-28"}'
curl -s http://127.0.0.1:8080/v1/backups/filesystem/backup-2026-08-28 \
-H "Authorization: Bearer $WEAVIATE_API_KEY" | jq '.status'
Два минуса: бэкап лежит на том же диске, который вы разгружали (забирайте его с сервера), и в существующую коллекцию не восстановится — класс должен отсутствовать заранее.
Какой сервер под Weaviate взять в MAATRIX
Сразу честно: Weaviate в каталоге apps.maatrix.io нет — сервер приезжает чистым (Ubuntu 24.04 или Debian 12), разворачиваете по compose из второй секции. В каталоге есть готовые сборки соседей по стеку — Qdrant, Ollama, LiteLLM, AnythingLLM, n8n — ставятся автоматически, доступы в кабинете: практичная схема — Ollama оттуда под эмбеддинги, Weaviate рядом руками.
Память считается арифметикой: число объектов × размерность × 4 байта (float32) — миллион фрагментов размерности 768 это ~2,9 ГБ, размерности 1024 — ~3,8 ГБ. Сверху граф HNSW, документация Weaviate советует закладывать вдвое больше самих векторов. Не помещаетесь — включайте сжатие: скалярное ужимает индекс в разы, бинарное — на порядок, ценой точности, которую добирают переранжированием.
Честный минимум: 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe. Хватает на 200–300 тысяч фрагментов при размерности 768 со сжатием и GOMEMLIMIT: 3GiB. На 1–2 ГБ Weaviate формально стартует, но первая массовая заливка запускает HNSW и компакцию одновременно — и уезжает в OOM.
Комфортный вариант: 4 vCPU, 8–16 ГБ RAM, 80–160 ГБ NVMe. Векторы и граф помещаются без ухищрений, индексация не конкурирует с поиском за ядра, есть место под бэкапы. Диск берите с двойным запасом: read-only включается на 90%. Если рядом Ollama — память под неё сверху: по нашим замерам на AMD EPYC 9554 (16 vCPU, Ollama 0.33.1) qwen2.5:7b в Q4_K_M занимает 5,1 ГБ, llama3.1:8b — 5,6 ГБ, qwen2.5:3b — 2,2 ГБ — на восьми гигабайтах вместе с Weaviate уже впритык.
Локация — Великобритания (Лондон). Рядом с векторной базой обычно сервис эмбеддингов, который ходит во внешние API, — из Лондона без региональных отказов, а до Европы канал короче: 40–60 мс из Москвы против вдвое большего RTT до Нью-Йорка. Данные и пользователи в России — берите RU: 152-ФЗ и пинг перевесят. Оплата — картами российских банков, СБП, криптой или токеном MAAT.
Если Weaviate избыточен — разбор соседа: Qdrant на сервере: частые ошибки. Сборка конвейера целиком: как поднять RAG по своим документам, VPS в Великобритании для нейросетей.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Клиент падает с WeaviateGRPCUnavailableError, хотя curl на 8080 отвечает. Почему?
Разные каналы: REST на 8080, gRPC на 50051, клиент v4 использует оба. Проверьте ss -tulpn | grep 50051, опубликуйте порт в Docker и фаерволе, а за Nginx настройте grpc_pass grpc://127.0.0.1:50051; с http2 on; — proxy_pass gRPC не проксирует.
Батч отработал без исключений, а объектов в коллекции нет. Куда они делись?
Клиент v4 не бросает исключение на ошибках батча: смотрите batch.number_errors при загрузке, collection.batch.failed_objects после. Причина обычно в первой ошибке — автосхема ждала строку, пришло число (not a string, but json.Number), либо коллекция мультитенантная, запрос ушёл без тенанта.
Запись отвалилась с store is read-only, место на диске уже освободил. Что дальше?
Weaviate переводит шарды в read-only выше DISK_USE_READONLY_PERCENTAGE (90% по умолчанию) и сам обратно не переключает. Смотрите шарды через GET /v1/schema/Document/shards, возвращайте статус PUT с телом {"status":"READY"}.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.