StackTraces
Meilisearch已驗證

Meilisearch search 傳 locales 報 invalid_search_locales

@debug_master6 天前更新閱讀 6 min00

在 search 請求體裡給 locales 傳了 "chinese"、"cn" 這類人類習慣叫法,Meilisearch 直接返回 400,錯誤碼 invalid_search_locales。locales 只認官方 ISO-639 取值,中文的合法值是 zh、zho、cmn,沒有 cn 也沒有 chinese。另外查詢側 locales 的優先級高於索引側 localizedAttributes,寫錯會覆蓋掉索引裡配好的語言。

Issue & Env(案發現場與環境)

  • 觸發場景:在 POST /indexes/{uid}/search 的請求體裡顯式指定 locales 來告訴 Meilisearch 查什麼語言,中文按口語/國家碼寫成了 "chinese" 或 "cn"。
  • 環境:Meilisearch v1.54.3,本機實跑復現。curl / 任意 SDK 只要把 locales 裡塞了非法值都會觸發。
  • 關鍵區分:這是一個同步返回的 400 校驗錯誤,不是異步任務失敗。請求根本沒進搜索流程,被參數校驗攔下了。合法的 locales 請求能正常返回命中(本機搜 {"q":"三体","locales":["cmn"]} 命中 id 1)。

StackTrace(堆疊日誌)

locales: ["chinese"] 的返回原文(message 裡的語言清單很長,中間截斷為 ...):

{"message":"Unknown value `chinese` at `.locales[0]`: expected one of `af`, `ak`, `am`, `ar`, ... `zh`, `zu`, `afr`, ... `zho`, `zul`, `cmn`","code":"invalid_search_locales","type":"invalid_request","link":"https://docs.meilisearch.com/errors#invalid_search_locales"}

locales: ["cn"] 是同一個錯誤碼,只是把值換掉:

{"message":"Unknown value `cn` at `.locales[0]`: expected one of `af`, `ak`, `am`, `ar`, ...","code":"invalid_search_locales","type":"invalid_request","link":"https://docs.meilisearch.com/errors#invalid_search_locales"}

注意報錯裡的路徑是 .locales[0](查詢側)。索引側設置寫錯非法 locale 時,錯誤碼是另一個:invalid_settings_localized_attributes,路徑是 [0].locales[0],別把兩者看成一回事。

Reproduce(復現程式碼)

# 合法:cmn 是中文的合法取值之一,正常返回命中
curl -s -X POST http://localhost:7700/indexes/books_zh/search \
  -H 'Authorization: Bearer aSampleMasterKey' \
  -H 'Content-Type: application/json' \
  -d '{"q":"三体","locales":["cmn"]}'

# 非法:chinese —— 返回 400 invalid_search_locales
curl -s -X POST http://localhost:7700/indexes/books_zh/search \
  -H 'Authorization: Bearer aSampleMasterKey' \
  -H 'Content-Type: application/json' \
  -d '{"q":"三体","locales":["chinese"]}'

# 非法:cn —— 同样 400 invalid_search_locales
curl -s -X POST http://localhost:7700/indexes/books_zh/search \
  -H 'Authorization: Bearer aSampleMasterKey' \
  -H 'Content-Type: application/json' \
  -d '{"q":"三体","locales":["cn"]}'

Root Cause(根因分析)

locales 只接受 ISO-639 取值

locales 不是自由文本,它按 ISO-639 標準校驗。英文裡可以寫 en/eng,中文對應的合法值是 zh、zho、cmn(cmn 是「官話」的 ISO 639-3 碼)。cn 是國家碼不是語言碼,chinese 是英文名也不是合法取值,兩者都會在校驗層被拒。

查詢側 locales 會覆蓋索引側設置

這點比報錯本身更容易被忽略:索引側可以通過 localizedAttributes 聲明「哪個字段是什麼語言」,而查詢側的 locales 優先級更高。如果索引裡已經把 *_zh 聲明成 cmn,查詢時又隨手傳了個錯的 locales,不僅會 400,即便僥倖寫了個別的合法 locale,也可能蓋掉索引裡的語言聲明,導致分詞行為和你預期不一致。要麼兩側對齊,要麼查詢側乾脆不傳、交給索引設置。

報錯信息裡能直接讀到合法值

錯誤 message 會把可接受取值整段列出來(af, ak, … zh, zu, afr, … zho, zul, cmn)。中文相關的就三個:zh、zho、cmn。不用去翻文檔,報錯裡就寫著。

The Fix(解決方案)

第一步:把 locales 改成合法值

中文用 cmn(或 zh/zho):

curl -s -X POST http://localhost:7700/indexes/books_zh/search \
  -H 'Authorization: Bearer aSampleMasterKey' \
  -H 'Content-Type: application/json' \
  -d '{"q":"三体","locales":["cmn"]}'

第二步:確認索引側聲明與查詢側一致

查詢側要傳 locales 時,先核對索引裡 localizedAttributes 是怎麼聲明的,讓兩側語言碼對上:

curl -s http://localhost:7700/indexes/books_zh/settings/localized-attributes \
  -H 'Authorization: Bearer aSampleMasterKey'

第三步:能不傳就不傳

如果索引已經用 localizedAttributes 配好了每種字段的語言,大多數情況下查詢側不需要再傳 locales,讓它走索引設置即可,省掉一類寫錯值的風險。

排查提示

  • 看到 invalid_search_locales 先看報錯裡的路徑:.locales[0] 是查詢側;[0].locales[0] 是索引側設置(對應 invalid_settings_localized_attributes)。
  • 國家碼(cn、us)、英文名(chinese、english)都不是合法值,用 ISO-639。
  • 單個請求可以傳多個 locale,按陣列順序生效;任何一個非法,整條請求都 400。

References(參考來源)

最後更新於 2026-10-05

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法