适用版本: 7.11-7.15
1. 错误异常的基本描述 #
Dynamic template [name] defines a runtime field but type [type] is not supported as runtime field 是 Elasticsearch 在解析动态模板(dynamic_templates)定义时抛出的映射解析异常。该错误表明:在动态模板中声明了运行时字段(runtime field),但指定的字段类型并不被运行时字段所支持。
运行时字段(runtime field)是 Elasticsearch 7.11 引入的特性,允许在索引映射中定义不占用存储、仅在查询时计算的字段。然而,并非所有字段类型都可以作为运行时字段使用,动态模板中的类型声明必须严格匹配运行时字段支持的类型列表。
常见现象 #
- 创建索引模板(index template)或更新索引映射(mapping)时,请求返回 HTTP
400错误,异常信息中明确包含Dynamic template和defines a runtime field but type关键字。 - Elasticsearch 服务端日志中会出现
MapperParsingException,并指出具体哪个动态模板名称和哪个类型不合法。 - 如果该模板已经关联到某个索引模式,则新索引在创建时(例如通过自动创建或 rollover)会持续失败,直到模板被修正。
- 使用 SDK 或自动化脚本批量创建模板时,同一批请求可能全部失败,影响索引的正常创建和数据的写入。
典型报错与异常栈 #
常见日志形态通常类似下面这样:
MapperParsingException[Dynamic template [strings] defines a runtime field but type [keyword] is not supported as runtime field]
at org.elasticsearch.index.mapper.DynamicTemplate.parse(DynamicTemplate.java:...)
at org.elasticsearch.index.mapper.MappingParser.parseDynamicTemplates(MappingParser.java:...)
at org.elasticsearch.index.mapper.MappingParser.parseMapping(MappingParser.java:...)
2. 为什么会发生这个错误 #
运行时字段(runtime field)虽然功能强大,但 Elasticsearch 对其支持的类型有严格限制。动态模板中如果同时设置了 runtime: true 并指定了一个不支持的字段类型,就会触发此异常。
常见原因通常包括:
- 类型不兼容:在动态模板中声明了
runtime: true,但mapping.type指定了不支持作为运行时字段的类型,例如keyword、text、nested、object、binary、geo_shape等。运行时字段仅支持long、double、date、boolean、ip、keyword(部分版本)、geo_point(部分版本)等有限类型。 - 动态模板结构错误:动态模板的格式不是标准的"具名对象数组"结构,或者模板中同时声明了
mapping和runtime两个冲突的配置项。 - 版本差异:不同版本的 Elasticsearch 对运行时字段支持的类型范围不同。例如在 7.11 早期版本中,支持的类型更少;而在 7.12+ 或 8.x 中,支持的类型有所扩展。使用高版本文档中的示例在低版本中执行,容易触发此错误。
- 残留配置迁移问题:从旧版本升级集群后,原有的动态模板中可能包含不再兼容的类型定义,导致新索引创建时失败。
3. 如何排查和解决这个异常 #
建议按"先定位模板、再确认类型、后修正配置"的顺序处理:
- 从报错信息中提取动态模板的名称(方括号中的内容),确认是哪个模板定义有问题。
- 通过
GET /_component_template或GET /_index_template获取相关模板的完整定义,重点检查dynamic_templates部分。 - 确认模板中
runtime字段的值,以及mapping.type指定的类型是否在当前版本运行时字段支持的类型列表中。 - 对照 Elasticsearch 官方文档 中对应版本的 Runtime fields 类型支持表,核验类型合法性。
- 在测试环境中使用修正后的模板定义创建索引,验证不再报错后,再应用到生产环境。
排查时需要注意的问题 #
- 不要只修正报错的单个模板,建议全面检查同一模板中所有动态模板的定义,避免遗漏其他潜在问题。
- 如果模板被多个索引模式引用,需要确认修正后的模板对所有关联索引均不会产生副作用。
- 涉及自动创建索引或 rollover 的场景,建议在修正模板后手动触发一次索引创建,验证修复效果。
4. 如何解决这个错误 #
常用修复思路 #
方案一:移除 runtime 声明,改为普通字段
如果业务上不需要运行时字段特性,只需将 runtime: true 移除,或将其改为 false:
{
"dynamic_templates": [
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
方案二:改为合法的运行时字段类型
如果确实需要使用运行时字段,将类型改为运行时字段支持的类型,例如 long、double、date、boolean、ip:
{
"dynamic_templates": [
{
"dates": {
"match_mapping_type": "string",
"runtime": true,
"mapping": {
"type": "date",
"format": "yyyy-MM-dd"
}
}
}
]
}
方案三:使用 runtime 顶层定义
在 Elasticsearch 7.12+ 中,可以直接在映射顶层定义运行时字段,而非通过动态模板:
{
"mappings": {
"runtime": {
"day_of_week": {
"type": "keyword"
}
},
"dynamic_templates": [
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
后续注意事项与推荐建议 #
- 在定义动态模板时,先确认目标类型是否支持作为运行时字段,避免直接套用旧版本或网络上的示例模板。
- 对关键索引模板建立版本管理机制,每次变更前在测试环境验证,并记录变更日志。
- 定期使用
GET /_index_template和GET /_component_template审计模板配置,及时发现不兼容的定义。 - 如果集群需要跨大版本升级,提前在测试环境验证所有模板的兼容性,必要时提前修正。
借助 INFINI 产品提升排障效率 #
- INFINI Console 适合查看集群索引模板、组件模板、动态模板的完整定义和状态,帮助快速定位不合法的模板配置。
- INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测和流量治理,可以在模板创建请求到达后端之前进行校验和拦截,防止不合法的模板定义进入集群。
- 建议将模板变更与索引创建失败的日志统一接入监控面板,在出现异常时第一时间收到告警。
5. 小结 #
Dynamic template defines a runtime field but type is not supported as runtime field 本质上是映射定义与运行时字段类型支持范围不匹配导致的解析异常。修复的核心在于:确认报错的动态模板名称,核验指定类型是否在当前版本运行时字段支持列表中,然后选择移除 runtime 声明或改用合法类型。
只要建立模板变更的验证流程,并结合 INFINI Console 和 INFINI Gateway 做好观测与防护,这类异常可以在萌芽阶段被发现和拦截。
相关错误 #
- a-file-written-by-master-to-the-store:主节点写入存储文件异常
- all-shards-failed:所有分片失败
- index-not-found-in-repository:仓库中未找到索引
附:日志上下文 #
下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:
} else if (matchMappingType != null) {
final XContentFieldType xContentFieldType;
try {
xContentFieldType = XContentFieldType.fromString(matchMappingType);
if (runtime && xContentFieldType.supportsRuntimeField() == false) {
throw new MapperParsingException("Dynamic template [" + name + "] defines a runtime field but type ["
+ xContentFieldType + "] is not supported as runtime field");
}
} catch (IllegalArgumentException e) {
if (indexVersionCreated.onOrAfter(Version.V_6_0_0_alpha1)) {
throw e;





