📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 6.8-8.9

1. 错误异常的基本描述 #

could not parse week times. expected an object; but found [token] 是 Elasticsearch Watcher 定时任务调度配置中常见的解析异常。当 Elasticsearch 在解析 weekly 类型的 schedule(调度计划)时,期望 times 字段是一个 JSON 对象(Object),但实际解析到的却是一个字符串、数组或其他非对象类型,就会抛出此异常。

该异常通常发生在以下场景中:

  • 创建或更新 Watcher 的 API 请求中,trigger.schedule.times 字段格式不正确。
  • 从旧版本 Elasticsearch 迁移 Watcher 配置时,schedule 结构发生了变化但配置未同步更新。
  • 通过脚本或自动化工具生成 Watcher 配置时,数据结构构造有误。
  • 手动编辑 Watcher JSON 配置时,误将 times 写成了字符串或数组而非对象。

常见现象 #

  • 调用 _watcher API 创建或更新 watch 时,返回 400 Bad Request 错误。
  • 响应体中包含 parse_exception 类型的错误信息,提示 could not parse week times. expected an object; but found [...]
  • Kibana 的 Watcher 管理界面可能无法保存配置,或显示校验错误。
  • 已有的 Watcher 在集群升级后可能无法加载,导致定时任务失效。

典型报错与异常栈 #

实际报错信息通常类似下面这样:

{
  "error": {
    "root_cause": [
      {
        "type": "parse_exception",
        "reason": "could not parse week times. expected an object; but found [VALUE_STRING]"
      }
    ],
    "type": "parse_exception",
    "reason": "could not parse week times. expected an object; but found [VALUE_STRING]"
  },
  "status": 400
}

服务端日志中可能出现的异常栈:

ElasticsearchParseException: could not parse week times. expected an object; but found [VALUE_STRING]
    at org.elasticsearch.xpack.watcher.trigger.schedule.WeekTimes.parse(WeekTimes.java)
    at org.elasticsearch.xpack.watcher.trigger.schedule.WeeklySchedule$Parser.parse(WeeklySchedule.java)
    at org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleRegistry.parse(ScheduleRegistry.java)

2. 为什么会发生这个错误 #

WeekTimes.parse 是 Elasticsearch Watcher 中专门用于解析每周调度时间的方法。Weekly Schedule 的设计需要同时描述星期几具体时间两个维度,因此其 times 配置必须是一个对象,才能完整表达这两个信息。

根本原因 #

WeekTimes.parse 方法的入口处会检查当前解析令牌(Token)类型,只有当令牌为 START_OBJECT 时才会继续解析,否则直接抛出 ElasticsearchParseException。这是因为:

  1. 对象结构才能承载完整信息weekly schedule 的 times 需要同时指定星期(on)和具体时刻(at),只有对象才能同时包含这两个字段。
  2. 解析器无法推断单一值含义:如果 times 只是一个字符串(如 "12:00")或数组(如 ["12:00"]),解析器无法判断这是指星期几、具体时间,还是其他含义。
  3. 与 yearly schedule 类似的约束YearTimes.parse 也有相同的约束,因为年度调度同样需要月份和日期两个维度。

常见错误写法 #

以下是几种常见的错误配置示例:

错误示例 1:将 times 写成字符串

{
  "trigger": {
    "schedule": {
      "weekly": {
        "times": "12:00"
      }
    }
  }
}

错误示例 2:将 times 写成数组

{
  "trigger": {
    "schedule": {
      "weekly": {
        "times": ["12:00", "18:00"]
      }
    }
  }
}

错误示例 3:遗漏 onat 字段

{
  "trigger": {
    "schedule": {
      "weekly": {
        "times": {
          "on": "monday"
        }
      }
    }
  }
}

3. 如何排查和解决这个异常 #

建议按以下步骤进行排查:

  1. 获取完整报错信息:查看 API 响应体或 Elasticsearch 日志,确认 token 的具体类型(如 VALUE_STRINGVALUE_ARRAY 等),这能直接指出配置中 times 的实际类型。
  2. 检查 Watcher 配置:通过 _watcher/watch/{watch_id} API 获取当前 watch 的完整配置,重点检查 trigger.schedule.weekly.times 的结构。
  3. 对照正确格式:参考官方文档或本文的正确示例,确认 times 是否为对象,且包含 onat 两个字段。
  4. 检查配置来源:如果配置来自脚本、模板或迁移工具,追溯生成逻辑,定位数据构造错误的位置。
  5. 验证修复结果:修改配置后,先通过 _watcher/watch/{watch_id}/_execute API 手动触发一次,确认不再报错。

排查时需要注意的问题 #

  • weekly schedule 的 timescron schedule 的语法完全不同,不要混淆两者。
  • 如果 Watcher 是从旧版本迁移过来的,注意 Elasticsearch 7.x 之后 Watcher 的 schedule 配置结构可能有变化。
  • on 字段的值不区分大小写,但必须是有效的星期名称(mondaytuesday 等),或使用数字 0-6(0 表示星期日)。
  • at 字段的值必须是合法的 24 小时制时间字符串,格式为 HH:mmHH:mm:ss

4. 如何解决这个错误 #

正确的配置格式 #

weekly schedule 的 times 必须是一个对象,包含 on(星期几)和 at(具体时间)两个字段:

正确示例 1:单个时间点

{
  "trigger": {
    "schedule": {
      "weekly": {
        "times": {
          "on": "monday",
          "at": "12:00"
        }
      }
    }
  }
}

正确示例 2:多个时间点(使用数组)

{
  "trigger": {
    "schedule": {
      "weekly": {
        "times": [
          {
            "on": "monday",
            "at": "09:00"
          },
          {
            "on": "friday",
            "at": "17:00"
          }
        ]
      }
    }
  }
}

正确示例 3:使用数字表示星期

{
  "trigger": {
    "schedule": {
      "weekly": {
        "times": {
          "on": 1,
          "at": "08:30"
        }
      }
    }
  }
}

完整的 Watcher 创建示例 #

以下是一个完整的 Watcher 配置示例,每周一和周五的中午 12 点执行:

PUT _watcher/watch/weekly_report
{
  "trigger": {
    "schedule": {
      "weekly": {
        "times": [
          {
            "on": "monday",
            "at": "12:00"
          },
          {
            "on": "friday",
            "at": "12:00"
          }
        ]
      }
    }
  },
  "input": {
    "search": {
      "request": {
        "indices": ["logs-*"],
        "body": {
          "query": {
            "range": {
              "@timestamp": {
                "gte": "now-7d"
              }
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": {
      "ctx.payload.hits.total": {
        "gt": 0
      }
    }
  },
  "actions": {
    "send_email": {
      "email": {
        "to": ["admin@example.com"],
        "subject": "Weekly Log Report",
        "body": "Found {{ctx.payload.hits.total}} log entries in the past 7 days."
      }
    }
  }
}

修复步骤 #

  1. 停止受影响的 Watcher(如果已存在):

    POST _watcher/watch/{watch_id}/_deactivate
    
  2. 更新配置,将 times 修正为正确的对象格式:

    PUT _watcher/watch/{watch_id}
    {
      "trigger": {
        "schedule": {
          "weekly": {
            "times": {
              "on": "monday",
              "at": "12:00"
            }
          }
        }
      }
    }
    
  3. 重新激活 Watcher

    POST _watcher/watch/{watch_id}/_activate
    
  4. 手动执行验证

    POST _watcher/watch/{watch_id}/_execute
    

后续注意事项与推荐建议 #

  • 在自动化生成 Watcher 配置时,加入 JSON Schema 校验,确保 times 字段结构正确后再提交到 Elasticsearch。
  • 对于复杂的调度需求,考虑使用 cron schedule 替代 weeklycron 表达式更灵活且不易出错:
    {
      "trigger": {
        "schedule": {
          "cron": "0 12 * * 1,5"
        }
      }
    }
    
  • 建立 Watcher 配置的版本管理机制,所有变更都经过测试环境验证后再应用到生产环境。
  • 定期检查 Watcher 的执行状态,通过 _watcher/stats API 监控是否有失败的 watch。

借助 INFINI 产品提升排障效率 #

  • INFINI Console 适合查看集群健康度、索引状态、错误趋势和请求画像,帮助快速判断 Watcher 相关异常是配置问题还是集群问题。
  • INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测、限流和流量治理,可以帮助捕获 Watcher API 的异常请求,便于排查配置错误。
  • 建议将 Watcher 执行日志、错误信息和变更记录统一接入监控面板,缩短从"发现问题"到"定位根因"的时间。

5. 小结 #

could not parse week times. expected an object; but found [...] 的核心原因是 weekly schedule 的 times 配置格式不正确——解析器期望一个对象(Object),却收到了其他类型的数据。只要确保 times 是一个包含 on(星期)和 at(时间)字段的对象,问题即可解决。

处理这类异常时,最有效的方法是先通过报错信息确认 times 的实际类型,再对照正确格式修正配置。对于需要复杂调度逻辑的场景,也可以考虑使用 cron schedule 替代 weekly,以减少配置错误的可能性。

相关错误 #

附:日志上下文 #

下面保留当前页面中的源码片段,便于结合异常调用栈定位问题:

public static WeekTimes parse(XContentParser parser, XContentParser.Token token) throws IOException, ElasticsearchParseException {
    if (token != XContentParser.Token.START_OBJECT) {
        throw new ElasticsearchParseException("could not parse week times. expected an object; but found [{}]", token);
    }
    // ... 继续解析 on 和 at 字段
}