Skip to content

fix(knowledge): answer a rejected kb path with 400 KNOWLEDGE_PATH_INVALID instead of 500 - #910

Open
Lesereingrape wants to merge 16 commits into
TencentCloud:developfrom
Lesereingrape:fix/kb-path-invalid-400
Open

Lesereingrape wants to merge 16 commits into
TencentCloud:developfrom
Lesereingrape:fix/kb-path-invalid-400

Conversation

@Lesereingrape

Copy link
Copy Markdown
Contributor

Summary

A knowledge path the server refuses to accept was answered as a server error. Two validators raise it and neither message was mapped:

  • normalize_kb_path() rejects a .. segment → ValueError("invalid knowledge document path") (src/octop/infra/knowledge/relpath.py:15)
  • KnowledgeRepo.ensure_folder() rejects a path that normalizes to empty — ".", "/", "///" → ValueError("invalid knowledge folder path") (src/octop/infra/db/repos/knowledge.py:259)

_map_knowledge_error() had branches for the name, size, limit, content-type and prerequisite rejections but none for these two, so they fell through to logger.exception(...) + INTERNAL_ERROR: HTTP 500, details.cause echoing an internal message, and a stack trace per request — while the sibling name check two lines above (:244) already answers 400 for the same class of caller input. CreateFolderBody.path only enforces min_length=1, so both spellings reach the service.

Both messages now map to a new KNOWLEDGE_PATH_INVALID (400). Deliberately not reusing KNOWLEDGE_NAME_INVALID, whose copy is "Invalid name." and would point at the wrong field. Which paths stay invalid is unchanged — only how the rejection is reported.

Per the i18n checklist in AGENTS.md §7, a new ErrorCode means four bundles: backend errors (en/zh) and dashboard apiErrors (en/zh). tests/unit/i18n/test_errors.py::test_dashboard_api_errors_match_backend and test_every_error_code_has_i18n_entry already enforce that parity, and both pass.

Fixes #909

Related open work

Recently merged PR #889 (2026-09-21, fix(knowledge): 删除文件夹时不再误删名字相近的文件夹) also touches infra/db/repos/knowledge.py, where these two ValueErrors are raised — but it changes which rows a folder delete matches, not how a rejection is reported. Re-read against develop @ e512f05b (this branch is rebased onto it): :259 still raises invalid knowledge folder path, relpath.py:15 still raises invalid knowledge document path, and _map_knowledge_error (knowledge_bases.py:201) still has no branch for either — it matches …document name only — so both still reach INTERNAL_ERROR on that head (measured: ".", "/", "..", "a/../b" → code=INTERNAL_ERROR status=500).

Target branch

  • Base is develop (feature / fix — default)
  • Base is main (release/* or hotfix/* only)

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Refactor / chore
  • Release / hotfix

Test plan

make is unavailable on this machine, so the .githooks/pre-commit gate (make all + dashboard build, per AGENTS.md §6/§10) never ran here — the commit was made without it. Its sub-targets were run individually and are quoted verbatim below.

RED — the committed tests, run against a tree that has the enum and the four locale bundles but
not the router branch (b46bb8a4 + this branch's files except knowledge_bases.py):

uv run pytest tests/unit/api/test_knowledge_bases.py tests/unit/i18n -q
→ 4 failed, 95 passed
  FAILED ::test_map_knowledge_error_invalid_path_is_client_error[invalid knowledge document path]
  FAILED ::test_map_knowledge_error_invalid_path_is_client_error[invalid knowledge folder path]
  FAILED ::test_create_folder_maps_invalid_path[../secret-invalid knowledge document path]
  FAILED ::test_create_folder_maps_invalid_path[.-invalid knowledge folder path]
    all four: AssertionError: assert <ErrorCode.INTERNAL_ERROR> == <ErrorCode.KNOWLEDGE_PATH_INVALID>

Behaviour, probed against KnowledgeRepo.ensure_folder fed to the router's own mapper (".", "/", "..", "a/../b" — all Pydantic-valid bodies), re-measured today on pristine develop @ e512f05b vs this branch:

before (e512f05b): '.' '/' '..' 'a/../b' -> code=INTERNAL_ERROR status=500
                   details={'cause': 'invalid knowledge folder path' | 'invalid knowledge document path'}
                   + one logger.exception stack per call
after  (this branch): code=KNOWLEDGE_PATH_INVALID status=400
                   envelope={'error': {'code': 'KNOWLEDGE_PATH_INVALID',
                                       'message': 'Invalid path.', 'details': {}}}

Final state on this branch (Windows / Python 3.12, head 2d3cbf33 on top of e512f05b; make test equivalents):

pytest tests/unit/api/test_knowledge_bases.py tests/unit/i18n tests/unit/knowledge tests/unit/test_errors.py -q
→ 187 passed
pytest tests/integration/test_knowledge_bases_api.py -m "not live" -q
→ 2 passed
pytest -n 4 -m "not live"        → 15 failed, 3502 passed, 118 skipped
pytest tests/unit/agents/test_memory_slim.py -q   on pristine e512f05b (same venv, same command)
→ 15 failed, 21 passed
  ↳ all 15 failures in the full run are in that one file, which #865 added to develop today;
    this branch changes no agent/memory code, so the delta vs its own base is 0 regressions
ruff check src tests            → All checks passed!
ruff format --check src tests   → 1049 files already formatted
mypy src/octop                  → Success: no issues found in 514 source files
  • Added/updated tests — 4 cases in tests/unit/api/test_knowledge_bases.py, following the existing test_rename_document_maps_invalid_name / test_map_knowledge_error_* idioms

Checklist

  • Updated CHANGELOG.md — one bullet at the top of ### 修复 under ## [Unreleased], citing (#909), landed as commit 2d3cbf33
  • README / docs updated (if needed) — not needed: docs/api.md documents the apiErrors mirroring mechanism, not individual codes

Not tested here: no live server run, so the repro is at the mapper + repo-validation level rather than a real HTTP response; the two dashboard locale files were not passed through Prettier (no node_modules on this box) — both lines copy the indentation and quoting of their neighbours; CI's Linux leg was not run locally.

Two validators reject a caller-supplied knowledge path with ValueError:
normalize_kb_path() for a ".." segment ("invalid knowledge document
path") and ensure_folder() for a path that normalizes to empty -- ".",
"/", which pass CreateFolderBody's min_length ("invalid knowledge folder
path"). _map_knowledge_error() had no branch for either message, so both
fell through to INTERNAL_ERROR: HTTP 500, details echoing an internal
message, and a logger.exception stack trace on every request. The sibling
name check two lines above already answers 400 for the same class of input.

Map both messages to a new KNOWLEDGE_PATH_INVALID rather than reusing
KNOWLEDGE_NAME_INVALID, whose copy ("Invalid name.") points at the wrong
field when the path is what was rejected. Which paths stay invalid is
unchanged here -- only how the rejection is reported.

A new ErrorCode needs all four locale bundles per the i18n checklist in
AGENTS.md: backend errors (en/zh) plus dashboard apiErrors (en/zh).
tests/unit/i18n/test_errors.py already fails if those key sets drift.
…d-400

CHANGELOG.md only: keep the entries added on develop since e512f05 and
place this fix's entry after them.
@Lesereingrape

Copy link
Copy Markdown
Contributor Author

CHANGELOG 冲突已解决(本 PR 与 #912 都会在 ### 修复 首行插入,此前在描述里预告过)。

  • 已把 origin/develop(21760bbf)合入分支,合并提交只改 CHANGELOG.md:保留 develop 自 e512f05b 以来新增的 7 条,本修复的条目排在其后;源码与测试文件一字未动,git diff origin/develop...HEAD 仍是原来的 8 files / +65。
  • 本地按上面的门控命令复跑:tests/unit/api/test_knowledge_bases.py → 29 passed;tests/unit/api → 283 passed, 10 skipped。
  • 提醒:这次 push 会让 CI 重新排队,需要再点一次 “Approve all and run”(上一轮两个 job 已在旧 head 2d3cbf33 上跑绿)。

…d-400

# Conflicts:
#	CHANGELOG.md
#	tests/unit/api/test_knowledge_bases.py
…d-400

# Conflicts:
#	tests/unit/api/test_knowledge_bases.py

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants