在 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(参考来源)
- Search with POST — Meilisearch 官方文档meilisearch-docs
- Error codes — Meilisearch 官方文档meilisearch-docs
- Settings — Meilisearch 官方文档meilisearch-docs
