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

这篇帮到你了吗?

刚解决了一个棘手的报错?花两分钟记录下来,帮助下一个遇到同样问题的开发者。

贡献一条解法