Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/en/faq/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,32 @@ pip install openviking --upgrade --force-reinstall

```

### After upgrading, the server won't start with `EmbeddingRebuildRequiredError`

`openviking-server` refuses to start when the embedding configuration (provider, model, or dimension) no longer matches the embedding metadata recorded in your existing vector collection — typically after an upgrade that changes the default embedding model. This is a deliberate safety stop so the server never mixes vectors from different embedding spaces, which would silently corrupt search results.

Your business data (resources, memories, and skills) is stored separately from the vector index and is **not** deleted — there is no need to wipe your workspace.

**Case 1 — only the provider/model changed, the embedding dimension is unchanged** (the common upgrade case):

1. Add `allow_metadata_override` to the `embedding` section of your `ov.conf`:
```json
{
"embedding": {
"allow_metadata_override": true
}
}
```
2. Restart `openviking-server`. It starts and keeps your existing vectors.
3. Refresh embeddings against the new model once the server is up:
```bash
ov reindex viking:// --mode vectors_only --sudo --wait true
```

**Case 2 — the embedding dimension changed:**

Existing vectors cannot be reused, and `allow_metadata_override` does **not** bypass a dimension change — the vector collection must be rebuilt from scratch. Back up your workspace first, then rebuild the `context` vector collection (this does not touch your source content, which is re-embedded during the rebuild). If you are unsure how to rebuild safely for your storage backend, ask on the [issue tracker](https://github.com/volcengine/OpenViking/issues) before deleting anything.

### How do I configure OpenViking?

Create an `~/.openviking/ov.conf` configuration file in your project directory:
Expand Down
26 changes: 26 additions & 0 deletions docs/zh/faq/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,32 @@ OpenViking 通过 Rust 绑定(`ragfs_python` / `RAGFSBindingClient`)在 Pyth
pip install openviking --upgrade --force-reinstall
```

### 升级后服务无法启动,报 `EmbeddingRebuildRequiredError`

当 embedding 配置(provider、model 或 dimension)与现有向量集合中记录的 embedding 元数据不一致时,`openviking-server` 会拒绝启动——通常发生在升级后默认 embedding 模型发生变化的场景。这是有意的安全保护:避免把来自不同 embedding 空间的向量混在一起,从而悄悄污染检索结果。

你的业务数据(resources、memories、skills)与向量索引分开存储,**不会**被删除——无需清空 workspace。

**情况 1 —— 仅 provider/model 变化、embedding dimension 不变**(常见的升级场景):

1. 在 `ov.conf` 的 `embedding` 段加上 `allow_metadata_override`:
```json
{
"embedding": {
"allow_metadata_override": true
}
}
```
2. 重启 `openviking-server`,服务会正常启动并保留现有向量。
3. 服务起来后,针对新模型刷新 embedding:
```bash
ov reindex viking:// --mode vectors_only --sudo --wait true
```

**情况 2 —— embedding dimension 发生了变化:**

现有向量无法复用,且 `allow_metadata_override` **不会**绕过维度变化——必须从头重建向量集合。请先备份 workspace,再重建 `context` 向量集合(不会动你的源内容,重建过程会重新生成 embedding)。如果不确定在你的存储后端下如何安全重建,删除任何数据前请先到 [issue tracker](https://github.com/volcengine/OpenViking/issues) 咨询。

### 如何配置 OpenViking?

在项目目录创建 `~/.openviking/ov.conf` 配置文件:
Expand Down
10 changes: 7 additions & 3 deletions examples/openclaw-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,12 +331,16 @@ OpenViking service logs:
cat ~/.openviking/data/log/openviking.log
```

### Web Console
### Web Studio

```bash
python -m openviking.console.bootstrap --host 0.0.0.0 --port 8020 --openviking-url http://127.0.0.1:1933
Web Studio is served by `openviking-server` itself — just open it in a browser, no separate process is needed:

```text
http://127.0.0.1:1933/studio
```

> The standalone `python -m openviking.console.bootstrap` console (port 8020) was removed in v0.3.18; use Web Studio at `/studio` instead.

### `ov tui`

```bash
Expand Down
10 changes: 7 additions & 3 deletions examples/openclaw-plugin/README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,16 @@ OpenViking 服务侧日志:
cat ~/.openviking/data/log/openviking.log
```

### Web Console
### Web Studio

```bash
python -m openviking.console.bootstrap --host 0.0.0.0 --port 8020 --openviking-url http://127.0.0.1:1933
Web Studio 由 `openviking-server` 内置提供,直接用浏览器打开即可,无需单独启动进程:

```text
http://127.0.0.1:1933/studio
```

> 独立的 `python -m openviking.console.bootstrap` 控制台(端口 8020)已在 v0.3.18 移除,请改用 `/studio`。

### `ov tui`

```bash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1134,11 +1134,9 @@ curl -sS "$OPENVIKING_BASE_URL/api/v1/content/read?uri=$(python3 -c 'import urll
# 服务端日志,路径以实际部署为准
tail -f ~/.openviking/data/log/openviking.log

# Web Console
python -m openviking.console.bootstrap \
--host 0.0.0.0 \
--port 8020 \
--openviking-url http://127.0.0.1:1933
# Web Studio:由 openviking-server 内置,浏览器打开即可,无需单独进程
# (独立 console 端口 8020 已在 v0.3.18 移除)
# 浏览器访问 http://127.0.0.1:1933/studio

# TUI
ov tui
Expand Down
45 changes: 44 additions & 1 deletion openviking/server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
)
from openviking.service.core import OpenVikingService
from openviking.service.task_tracker import get_task_tracker
from openviking.storage.errors import EmbeddingRebuildRequiredError
from openviking_cli.exceptions import OpenVikingError
from openviking_cli.utils import get_logger
from openviking_cli.utils.config import get_openviking_config
Expand Down Expand Up @@ -114,13 +115,55 @@ async def _initialize_api_key_manager(
)


def _format_embedding_rebuild_guidance(exc: EmbeddingRebuildRequiredError) -> str:
"""Build an operator-facing recovery message for an embedding-incompatible startup.

The server refuses to start when persisted vectors no longer match the embedding
configuration (e.g. after an upgrade that changes the embedding provider/model/
dimension). Without this, the only signal is a bare traceback with no recovery
path, which pushes operators toward deleting business data (issue #2273).
"""
return (
"OpenViking cannot start: the existing vector collection is incompatible "
"with the current embedding configuration.\n"
f" Reason: {exc}\n"
"\n"
"This usually happens after upgrading OpenViking when the embedding "
"provider, model, or dimension changed. The server stops on purpose so it "
"never mixes vectors from different embedding spaces, which would silently "
"corrupt search results.\n"
"\n"
"Recover WITHOUT deleting business data (resources, memories, and skills are "
"stored separately from the vector index and are preserved):\n"
" - Provider/model changed, embedding DIMENSION unchanged:\n"
' 1. Add "embedding": {"allow_metadata_override": true} to your ov.conf\n'
" 2. Restart openviking-server (it starts and keeps the existing vectors)\n"
" 3. Refresh embeddings against the new model once the server is up:\n"
" ov reindex viking:// --mode vectors_only --sudo --wait true\n"
" - Embedding DIMENSION changed: existing vectors cannot be reused, and "
"allow_metadata_override does NOT bypass a dimension change. The vector index "
"must be rebuilt from scratch; follow the rebuild procedure in the upgrade "
"guide below. Source content is preserved and is re-embedded during the "
"rebuild.\n"
"\n"
"Upgrade & troubleshooting guide: "
"https://github.com/volcengine/OpenViking/blob/main/docs/en/faq/faq.md"
)


async def _initialize_runtime_state(
app: FastAPI,
service: OpenVikingService,
config: ServerConfig,
) -> None:
"""Initialize service and auth dependencies before traffic is accepted."""
await service.initialize()
try:
await service.initialize()
except EmbeddingRebuildRequiredError as exc:
# Turn an expected-but-fatal upgrade condition into actionable guidance,
# then re-raise so startup still aborts — never serve incompatible vectors.
logger.error(_format_embedding_rebuild_guidance(exc))
raise
await _initialize_api_key_manager(app, service, config)
logger.info("OpenVikingService initialization complete")

Expand Down
59 changes: 58 additions & 1 deletion tests/server/test_server_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@
import httpx
import pytest

from openviking.server.app import _initialize_runtime_state, _on_deferred_init_done, create_app
from openviking.server.app import (
_format_embedding_rebuild_guidance,
_initialize_runtime_state,
_on_deferred_init_done,
create_app,
)
from openviking.server.config import ServerConfig
from openviking.storage.errors import EmbeddingRebuildRequiredError


class _ExitCalled(Exception):
Expand Down Expand Up @@ -327,3 +333,54 @@ async def load(self):
assert service._initialized is True
assert app.state.api_key_manager is not None
assert app.state.api_key_manager.loaded is True


def test_embedding_rebuild_guidance_is_actionable():
"""The startup guidance must give operators a concrete, non-destructive recovery path."""
exc = EmbeddingRebuildRequiredError(
"Existing collection embedding dimension (1024) does not match current "
"configuration (512). Vectors are incompatible; rebuild is required."
)
msg = _format_embedding_rebuild_guidance(exc)

# Echoes the original reason so the operator knows which mismatch occurred.
assert "dimension (1024) does not match" in msg
# Names the non-destructive flag for the provider/model-only (same dimension) case.
assert "allow_metadata_override" in msg
# Points to the re-embedding command for refreshing vectors.
assert "ov reindex" in msg
# Distinguishes the two failure cases (dimension changed vs. provider/model changed).
assert msg.lower().count("dimension") >= 2
# Links operators to the upgrade/FAQ guidance.
assert "faq" in msg.lower() or "upgrade" in msg.lower()


async def test_initialize_runtime_state_surfaces_embedding_rebuild_guidance(monkeypatch):
"""An embedding-incompatible startup must log actionable guidance and still fail loud."""

class _RebuildService:
def __init__(self):
self.viking_fs = object()

async def initialize(self):
raise EmbeddingRebuildRequiredError(
"Existing collection embedding metadata does not match current configuration."
)

logged: list[str] = []
monkeypatch.setattr(
"openviking.server.app.logger.error",
lambda msg, *args, **kwargs: logged.append(str(msg)),
)

app = SimpleNamespace(state=SimpleNamespace(api_key_manager=None))
service = _RebuildService()
config = ServerConfig(root_api_key="root-key-for-test")

# Must re-raise so uvicorn aborts startup — never serve with incompatible vectors.
with pytest.raises(EmbeddingRebuildRequiredError):
await _initialize_runtime_state(app, service, config)

joined = "\n".join(logged)
assert "allow_metadata_override" in joined
assert "ov reindex" in joined