Report a stemless --db path as a usage error and separate the two lancedb.uri migrations

An empty lancedb.uri, which init-config used to emit, is told to remove the
key; only a non-empty value is told the databases spelling. haiku-rag --db
and haiku-ingester --db turn a path with no stem into typer.BadParameter.
This commit is contained in:
Yiorgis Gozadinos 2026-09-03 14:54:37 +03:00
parent a04a16c717
commit 3814b2bc78
No known key found for this signature in database
7 changed files with 52 additions and 6 deletions

View file

@ -24,7 +24,8 @@
- Every database has a name: the key in `lancedb.databases`, or the path's stem
for `--db PATH`, `db_path=` and the default database, which is the entry
`haiku.rag` under `storage.data_dir` and selectable by that name.
`SearchResult.source`, `Document.source` and `Citation.source` always carry it.
`SearchResult.source`, `Document.source` and `Citation.source` carry it on
every value a database produces.
- `db_path=` beside a configured `lancedb.databases` raises
`AmbiguousDatabaseError` (`HaikuRAG`, `create_capability`, `create_mcp_server`,
`Sandbox`). `haiku-rag --db PATH` and `haiku-ingester --db PATH` open that path

View file

@ -102,7 +102,10 @@ def resolve_scope(
"pass --db or --db-name, not both: they name the same thing"
)
if db is not None:
return DatabaseScope.at(db)
try:
return DatabaseScope.at(db)
except ValueError as error:
raise typer.BadParameter(str(error), param_hint="--db") from error
scope = DatabaseScope.resolve(get_config(), database_name=_db_name)
if scope.covers_multiple and not covers_set:
raise AmbiguousDatabaseError(

View file

@ -120,9 +120,14 @@ class LanceDBConfig(ConfigModel):
@classmethod
def _uri_names_its_replacement(cls, data: Any) -> Any:
if isinstance(data, dict) and "uri" in data:
if str(data["uri"]).strip():
raise ValueError(
"lancedb.uri was removed; write lancedb.databases: {NAME: "
f"{data['uri']!r}}} instead"
)
raise ValueError(
"lancedb.uri was removed; write lancedb.databases: {NAME: "
f"{data['uri']!r}}} instead"
"lancedb.uri was removed; remove the empty key. With no "
"lancedb.databases the database is haiku.rag under storage.data_dir"
)
return data

View file

@ -224,7 +224,12 @@ def _scope_for(db: Path | None) -> "DatabaseScope | None":
is configured. None leaves placement to the configuration."""
from haiku.rag.client.scope import DatabaseScope
return DatabaseScope.at(db) if db is not None else None
if db is None:
return None
try:
return DatabaseScope.at(db)
except ValueError as error:
raise typer.BadParameter(str(error), param_hint="--db") from error
@_cli.command("serve")

View file

@ -547,6 +547,16 @@ class TestPlacingTheIngesterDatabase:
tmp_path / "local.lancedb"
)
def test_a_path_without_a_stem_is_a_usage_error(self):
from pathlib import Path
import typer
from haiku.rag.ingester.cli import _scope_for
with pytest.raises(typer.BadParameter, match="no name"):
_scope_for(Path("/"))
def test_a_python_caller_cannot_pass_a_path(self):
from haiku.rag.ingester.app import IngesterApp

View file

@ -169,6 +169,16 @@ class TestOneDatabaseCommands:
assert scope.names == ("other",)
assert not scope.covers_multiple
def test_a_path_without_a_stem_is_a_usage_error(self, monkeypatch):
"""A path that names no database is the operator's mistake, reported as
one."""
import typer
self._install(monkeypatch)
with pytest.raises(typer.BadParameter, match="no name"):
resolve_scope(Path("/"))
def test_no_configured_databases_is_allowed(self, monkeypatch, tmp_path):
import haiku.rag.config as config_module

View file

@ -812,7 +812,19 @@ def test_lancedb_uri_is_refused_with_the_replacement_named():
message = str(raised.value)
assert "lancedb.uri" in message
assert "lancedb.databases" in message
assert "lancedb.databases: {NAME: 's3://bucket/notes.lancedb'}" in message
with pytest.raises(ValidationError, match="lancedb.databases"):
LanceDBConfig.model_validate({"uri": "/data/notes.lancedb"})
def test_an_empty_lancedb_uri_is_refused_with_removal_as_the_remedy():
"""Generated configs carried `uri: ""` for the local default. The remedy is
to delete the key, never a mapping with an empty location."""
with pytest.raises(ValidationError) as raised:
AppConfig.model_validate({"lancedb": {"uri": ""}})
message = str(raised.value)
assert "lancedb.uri" in message
assert "remove" in message
assert "{NAME" not in message