fix(dialog): guard async_ask() against empty or invalid kb_ids (#15530)

Fixes #15529 .

### Problem

`async_ask()` accessed `kbs[0]` without verifying that
`KnowledgebaseService.get_by_ids()` returned any knowledge bases. Empty
or stale `kb_ids` raised `IndexError`, which surfaced as HTTP 500 on
search/bot SSE endpoints.

### Fix

- Add an early guard when `kbs` is empty, yielding a final SSE error
event (consistent with `gen_mindmap()` in the same module).
- Add regression tests for empty `kb_ids` and deleted/invalid KB IDs.

### Test plan

- [ ] `pytest
test/unit_test/api/db/services/test_dialog_service_final_answer.py -k
"async_ask_empty or async_ask_stale"`
- [ ] Manual: `POST /api/v1/searchbots/ask` with invalid `kb_ids`
returns SSE error, not HTTP 500

---------

Co-authored-by: Wang Qi <wangq8@outlook.com>
This commit is contained in:
bohdansolovie
2026-06-11 15:52:59 +08:00
committed by GitHub
parent de18313f97
commit 381091df71
2 changed files with 55 additions and 0 deletions

View File

@@ -292,6 +292,53 @@ def test_async_ask_delta_events_carry_incremental_text_only(monkeypatch):
)
@pytest.mark.p2
def test_async_ask_empty_kb_ids_yields_error_final_event(monkeypatch):
"""
When kb_ids is empty, async_ask() must not crash with IndexError on kbs[0].
"""
monkeypatch.setattr(
dialog_service.KnowledgebaseService, "get_by_ids", lambda _ids: []
)
events = _collect(
dialog_service.async_ask(
question="What is RAGFlow?",
kb_ids=[],
tenant_id="tenant-1",
)
)
assert len(events) == 1
final = events[0]
assert final.get("final") is True
assert "No KB selected" in final["answer"]
assert final["reference"] == {}
@pytest.mark.p2
def test_async_ask_stale_kb_ids_yields_error_final_event(monkeypatch):
"""Provided kb_ids that do not resolve to any KB should report invalid selection."""
monkeypatch.setattr(
dialog_service.KnowledgebaseService,
"get_by_ids",
lambda ids: [] if ids == ["deleted-kb"] else [_KB],
)
events = _collect(
dialog_service.async_ask(
question="What is RAGFlow?",
kb_ids=["deleted-kb"],
tenant_id="tenant-1",
)
)
assert len(events) == 1
assert events[0].get("final") is True
assert "not valid" in events[0]["answer"]
assert events[0]["reference"] == {}
# ---------------------------------------------------------------------------
# Tests for async_chat (production code path)
# ---------------------------------------------------------------------------