dapr v1.17.2 版本更新介绍
发布日期: 2026-03-19
版本号: v1.17.2
Dapr 1.17.2版本更新包含多项安全修复、一个破坏性变更、新增组件及错误修复:升级Go至1.25.8以修复标准库安全漏洞;正式注册RavenDB状态存储组件;修正工作流状态保留策略CRD字段类型(破坏性变更,需手动更新CRD);解决发布订阅消息在优雅关闭时误路由至死信队列、调度器作业重连时可能重复触发、调度器因DNS查询末尾点号无法启动等问题;优化服务调用避免为流式请求/响应体全量缓冲内存;修复Oracle数据库状态存储BulkGet返回整体500错误而非逐键错误;解决Pulsar发布订阅配置Avro模式时发送无效JSON、大量副本时Actor传播失败、LangChain Go Kit日志空指针引用、工作流活动大结果触发gRPC资源耗尽错误、批量发布未添加命名空间前缀、工作流计时器提醒未在超时前事件接收时删除、Ollama对话组件规格缺少端点字段、MongoDB作为工作流Actor状态存储时CLI无法列出工作流实例、LangChain Go Kit未执行必需工具调用时未返回错误、以及Sentry签名证书时密钥类型与CSR签名算法不匹配等问题。
更新内容 (中文)
Dapr 1.17.2
此更新包含安全修复、一项破坏性变更、一个新组件及多项错误修复:
- 通过升级到Go 1.25.8修复Go标准库漏洞
- 注册RavenDB状态存储组件
- 工作流状态保留策略CRD字段使用错误类型(破坏性变更)
- 优雅关闭期间发布/订阅消息被错误路由到死信队列
- 具有丢弃失败策略的调度器作业在主机重连期间可能触发多次
- 调度器因集群域DNS查找中的尾部点而无法启动
- 服务调用将整个流式请求体缓冲在内存中
- 服务调用将整个流式响应体缓冲在内存中
- Oracle数据库状态存储BulkGet返回HTTP 500而非每个键的错误
- 配置Avro模式时Pulsar发布/订阅发布无效的JSON消息
- 具有多个副本的Actor放置分发失败
- 会话LangChain Go Kit LLM日志记录器中的空指针解引用
- 具有大型结果的工作流活动因gRPC ResourceExhausted错误而失败
- 批量发布未向主题添加命名空间前缀
- 在超时前接收到外部事件时,工作流计时器提醒未被删除
- Ollama会话组件规范中缺少端点元数据字段
- 使用MongoDB作为工作流Actor状态存储时,Dapr CLI无法列出工作流实例
- LangChain Go Kit会话组件在未调用必需工具调用时不返回错误
- 当颁发者密钥类型与CSR签名算法不匹配时,Sentry无法签署证书
通过升级到Go 1.25.8修复Go标准库漏洞
问题
在Dapr 1.17.1使用的Go标准库(Go 1.24.13)中发现了三个漏洞:
- GO-2026-4603:
html/template中元内容属性操作中的URL未被转义,允许通过精心构造的URL进行潜在的跨站脚本攻击。 - GO-2026-4602:
os中的FileInfo可能从Root中逃逸,可能允许访问预期目录边界之外的文件。 - GO-2026-4601:
net/url中IPv6主机字面量的错误解析,可能导致在解析用户提供的URL的应用程序中出现意外的URL路由或SSRF。
影响
使用html/template、os.Root作用域文件操作或net/url URL解析的应用程序可能受到这些漏洞的影响。所有三个漏洞均已在Go 1.25.8中修复。
根因
这些漏洞存在于Go标准库中,并非Dapr代码特有。它们影响任何使用低于1.25.8版本的Go编译的Go程序。
解决方案
将Go工具链从1.24.13升级到1.25.8,涉及存储库中的所有模块和Docker镜像。
注册RavenDB状态存储组件
问题
来自components-contrib的RavenDB状态存储组件未在Dapr运行时中注册,因此无法在Dapr应用程序中用作状态存储。
影响
尽管组件实现已在components-contrib中提供,但用户无法将RavenDB用作Dapr的状态存储后端。
根因
RavenDB状态存储的组件注册文件在Dapr运行时的组件加载器(cmd/daprd/components/)中缺失。
解决方案
添加了state_ravendb.go注册文件,将RavenDB状态存储组件注册到默认状态存储注册表中。该组件在使用allcomponents构建标签构建时可用。在go.mod中添加了ravendb-go-client依赖项。
工作流状态保留策略CRD字段使用错误类型(破坏性变更)
问题
Configuration CRD将stateRetentionPolicy字段(anyTerminal、completed、failed、terminated)定义为type: integer, format: int64,但Go API类型使用metav1.Duration,该类型序列化为字符串(例如"1s"、"168h")。
这种不匹配导致Kubernetes拒绝这些字段的有效持续时间字符串值,并阻止通过Kubernetes Configuration CRD正确配置工作流状态保留策略。
影响
在Kubernetes模式下运行Dapr的用户无法使用Configuration CRD配置工作流状态保留策略,因为诸如"1s"或"168h"之类的人类可读持续时间字符串被Kubernetes验证拒绝,因为CRD架构期望整数。
此外,即使使用整数纳秒值来绕过CRD架构验证,内部配置反序列化器也无法正确解组由Operator发送的metav1.Duration字符串格式,导致daprd失败并出现:
运行时致命错误:加载配置时出错:json:无法将字符串解组到Go结构体字段WorkflowStateRetentionPolicy.spec.workflow.stateRetentionPolicy.anyTerminal的类型time.Duration
根因
Configuration CRD YAML(charts/dapr/crds/configuration.yaml)在Go API类型WorkflowStateRetentionPolicy更新为使用*metav1.Duration字段后未重新生成。
解决方案
更新了CRD架构,对所有stateRetentionPolicy字段使用type: string,与metav1.Duration序列化格式匹配。
在内部config.WorkflowStateRetentionPolicy结构体上添加了自定义的UnmarshalJSON方法,该方法通过configapi.WorkflowStateRetentionPolicy类型(使用*metav1.Duration)进行反序列化,正确处理Kubernetes CRD字符串格式和独立YAML格式。
升级
这是一个需要CRD更新的变更。 Kubernetes在通过Helm升级Dapr时不会自动更新CRD。 您必须在升级前手动更新CRD。 有关如何强制更新CRD的详细说明,请参阅Kubernetes升级指南。
手动更新CRD:
kubectl apply -f https://raw.githubusercontent.com/dapr/dapr/v1.17.2/charts/dapr/crds/configuration.yaml
优雅关闭期间发布/订阅消息被错误路由到死信队列
问题
在优雅关闭(或发布/订阅组件的热重载)期间,订阅开始关闭后到达的消息会被Dapr立即NACK。 支持死信队列的代理将这些NACK解释为永久性传递失败,并将消息路由到死信队列,在那里永远不会重试。
影响
使用配置了死信队列的发布/订阅的应用程序在滚动部署、重启或任何触发优雅关闭的事件期间可能丢失消息。 这些消息未被重新传递给另一个健康的消费者,而是被静默地转移到死信队列。 这影响所有订阅类型:声明式、编程式(HTTP和gRPC)和流式订阅。
根因
当订阅正在关闭时,Dapr拒绝新的传入消息,并返回"订阅已关闭"错误。 可插拔的发布/订阅组件层将此错误转换为发送回代理的NACK。 然后代理将消息视为永久性失败,并将其路由到配置的死信主题。
解决方案
Dapr现在在订阅关闭期间暂存到达的消息,而不是拒绝它们。 消息处理程序阻塞,直到代理连接断开,此时代理将消息视为未确认,并将其重新传递给另一个可用的消费者。 已在处理中的消息继续正常完成,然后订阅才会完全关闭。
具有丢弃失败策略的调度器作业在主机重连期间可能触发多次
问题
当调度器集群成员身份发生变化(包括初始启动期间)时,一次性作业或具有丢弃失败策略的作业可能被触发多次。
影响
配置了DueTime(一次性)或Drop失败策略的作业可能会被多次传递给应用程序,而不是最多一次。
这在调度器启动或调度器集群成员身份发生变化时更可能发生,因为etcd可能会在短时间内发出多个成员身份事件。
根因
在daprd的调度器连接管理中的两个异步事件循环之间存在竞争条件。 _主机循环_管理到调度器的gRPC客户端连接,_连接器循环_管理运行在这些连接上的基于流的集群。
当主机循环接收到第二组调度器主机地址(例如,启动期间的etcd成员身份事件)时,它在连接器循环有机会优雅停止运行在这些连接上的集群之前立即关闭了第一组gRPC客户端连接。 这导致活动流在进行中断开,进行中的作业触发被标记为无法投递并重新暂存,以及当新流连接时作业再次触发。
解决方案
将gRPC连接生命周期管理从主机循环移至连接器循环。
主机循环现在通过Connect事件将连接关闭函数传递给连接器,并且连接器在优雅停止先前集群后才关闭旧连接。
这确保了在流仍然活动时永远不会关闭连接。
调度器因集群域DNS查找中的尾部点而无法启动
问题
Dapr调度器服务在Kubernetes中启动失败,出现致命错误:
运行时致命错误:调度器启动失败:创建etcd配置时出错:对等证书不包含预期的DNS名称dapr-scheduler-server-1.dapr-scheduler-server.dapr-system.svc.cluster.local.,得到[dapr-scheduler-server-0.dapr-scheduler-server.dapr-system.svc.cluster.local dapr-scheduler-server-1.dapr-scheduler-server.dapr-system.svc.cluster.local dapr-scheduler-server-2.dapr-scheduler-server.dapr-system.svc.cluster.local]
影响
调度器服务无法在任何Kubernetes集群中启动,因为集群域的DNS CNAME查找返回带有尾部点的完全限定域名(标准DNS行为)。这会阻止所有基于调度器的功能,包括作业调度。
根因
调度器通过DNS CNAME查找解析Kubernetes集群域。根据DNS惯例,CNAME响应包含尾部点(例如cluster.local.)。
代码仅剥离结果中的前导点,留下了尾部点。
这导致etcd对等TLS服务器名称以额外的点结尾,与证书SANs不匹配并导致验证失败。
解决方案
将strings.TrimLeft更改为strings.Trim,以剥离解析的集群域两端的点,确保从DNS CNAME响应中移除尾部点。
服务调用将整个流式请求体缓冲在内存中
问题
通过Dapr HTTP服务调用发送带有流式主体(分块传输编码)的请求时,sidecar在转发之前将整个请求主体缓冲在内存中。 对于大型有效载荷(如文件上传或长时间运行的数据流),这会导致过度的内存使用和潜在的内存不足崩溃。
影响
任何没有已知Content-Length的HTTP服务调用请求(例如分块上传、流式数据、管道化主体)都会被发送端sidecar将整个主体缓冲在内存中。
这使得Dapr不适合在服务之间流式传输大型有效载荷,并可能导致生产环境中的sidecar OOM被终止。
根因
sidecar的重试机制无条件地将请求主体缓冲到内存中,以便在重试时重放主体。 对于流式请求,主体无法重放,因为它在读取时被消耗,使得缓冲既不必要又有害。
解决方案
sidecar现在检测流式请求(那些没有已知内容长度的请求),并完全跳过请求主体缓冲。
对于流式请求,内置重试逻辑和任何用户配置的弹性重试策略都会自动绕过,因为重试将需要重新读取已被消耗的主体。
具有已知Content-Length的非流式请求继续按以前支持重试。
服务调用将整个流式响应体缓冲在内存中
问题
通过服务调用代理HTTP响应时,sidecar在将响应转发给调用者之前将整个响应主体缓冲在内存中。 对于大型或无界的流式响应,这会导致过度的内存使用和潜在的内存不足崩溃。
影响
任何具有大型或流式主体的服务调用响应都可能导致sidecar OOM被终止,而不管HTTP状态码如何。 这使得Dapr不适合代理流式响应,如服务器发送的事件、文件下载或服务之间长时间运行的数据流。
根因
sidecar的弹性机制将完整的响应主体读入内存,以便评估是否重试请求。 当请求本身是已被消耗的流时,无论如何都无法重试,使得缓冲既不必要。
解决方案
对于流式请求,sidecar现在直接将响应主体转发给调用者,而不将它们缓冲在内存中。 弹性功能(如断路器)继续正常跟踪失败。 非流式请求继续按以前支持重试和缓冲错误处理。
Oracle数据库状态存储BulkGet返回HTTP 500而非每个键的错误
问题
使用Oracle数据库状态存储组件时,遇到一个或多个键错误的BulkGet请求返回整个请求的HTTP 500错误,而不是在成功结果旁返回每个键的错误。
影响
使用Oracle数据库状态存储进行BulkGet的应用程序,如果只有一个键遇到错误,就无法检索任何结果。没有收到有效键的成功结果和失败键的每个键错误,整个操作以HTTP 500响应失败。
根因
Oracle数据库状态存储组件中的BulkGet实现,在任何单个键检索失败时返回顶层错误,而不是收集错误并将其与响应中的特定键关联。
解决方案
更新了BulkGet实现,以在BulkGetResponse项中返回每个键的错误,而不是返回顶层错误。成功的键检索现在与任何每个键错误一起返回,符合预期的状态存储BulkGet约定。
配置Avro模式时Pulsar发布/订阅发布无效的JSON消息
问题
当Pulsar发布/订阅组件配置了Avro模式时,JSON消息在未经模式验证的情况下被发布。不符合Avro模式的无效消息被接受并发布到主题。
影响
依赖Pulsar发布/订阅层强制执行Avro模式的应用程序可能会发布不符合预期模式的畸形消息。期望模式符合消息的下游消费者可能会遇到反序列化失败或数据完整性问题。
根因
Pulsar发布/订阅组件在发布前未根据配置的Avro模式验证JSON消息有效负载。该模式仅用于消费者端的反序列化,而未用于生产者端的验证。
解决方案
在发布路径中添加了JSON到Avro模式的验证。在发布前,该组件现在根据配置的Avro模式验证JSON消息有效负载,如果消息不符合则返回错误,防止无效消息被发布到主题。
具有多个副本的Actor放置分发失败
问题
升级到Dapr 1.17.x后,具有多个副本(例如50+)的部署经常出现"分发在8秒后超时"错误,且/placement/state仅显示预期主机的一小部分。
影响
Actor调用间歇性失败,因为大多数sidecar从未收到完整的放置表。滚动重启和缩放事件放大了这个问题,使得大型Actor部署不稳定。
根因
三个问题共同导致分发期间的级联故障:
- 接受过时的UNLOCK版本:sidecar分发器在将传入版本与当前版本进行比较之前分配了它,因此守卫
currentVersion > version始终评估为false。过时的UNLOCK消息被错误地应用。 - 错误永久终止分发器:当sidecar在UPDATE时检测到版本不匹配或收到未知操作时,它返回一个致命错误,完全终止了分发器循环。sidecar从未重新连接到放置服务并保持卡住状态。
- 为并发连接进行顺序分发轮次:当许多副本同时连接到放置服务,而分发轮次正在进行时,每个等待连接在完成时都会触发自己的顺序分发轮次。如果有N个等待副本,则创建N轮而不是1轮,导致超时并断开其他sidecar连接,产生级联故障。
解决方案
- 修复了UNLOCK版本守卫,使其在分配前进行比较,因此过时版本被正确拒绝。
- 将版本不匹配和未知操作处理更改为取消流并触发干净重新连接,而不是终止分发器。
- 将所有在活跃分发轮次期间到达的连接批处理到一个轮次中,将N个顺序轮次减少到1个。
会话LangChain Go Kit LLM日志记录器中的空指针解引用
问题
使用LangChain Go Kit的会话组件在调用LLM日志记录器时可能因空指针解引用而发生恐慌。
影响
使用基于LangChain Go Kit组件的会话API的应用程序可能因空指针解引用而发生意外崩溃,导致Dapr sidecar重启。
根因
LangChain Go Kit会话组件中的LLM日志记录器回调被空指针调用,并且日志记录器在访问指针之前未执行空值检查。
解决方案
在LangChain Go Kit LLM日志记录器中添加了空指针检查以防止解引用,确保会话组件优雅处理该情况而不会恐慌。
具有大型结果的工作流活动因gRPC ResourceExhausted错误而失败
问题
返回大于约2MB结果的工作流活动在通过调度器调度活动结果提醒时因ResourceExhausted gRPC错误而失败:
由于以下原因无法安排提醒作业activity-result-XXXX:rpc错误:代码=ResourceExhausted描述=尝试发送的消息大于最大值(37950104对2097152)
影响
任何返回大于默认gRPC发送消息大小限制(约2MB)结果的工作流活动都无法将其结果传回父编排。编排无限期地等待活动结果,最终超时或停滞。
根因
调度器gRPC客户端配置了MaxCallRecvMsgSize以允许接收大消息,但未配置MaxCallSendMsgSize。这使得发送端限制保持在gRPC默认值(约2MB)。当活动完成时,其结果被序列化为发送给调度器的提醒作业请求。如果活动结果超过默认限制,gRPC客户端在到达服务器之前拒绝传出消息。
解决方案
在调度器gRPC客户端拨号选项中添加了MaxCallSendMsgSize,与现有的MaxCallRecvMsgSize配置匹配。
批量发布未向主题添加命名空间前缀
问题
使用启用了NamespaceScoped的发布/订阅组件的批量发布API时,消息被发布到无命名空间前缀的主题,而不是命名空间前缀的主题。
影响
使用命名空间范围发布/订阅组件和批量发布API的应用程序经历了静默消息丢失。批量发布的消息被路由到错误的主题(例如无命名空间的交换机),而订阅者正在监听命名空间前缀的主题。常规Publish API未受影响,因此只有批量发布用户遇到此问题。
根因
publisher.go中的Publish方法在NamespaceScoped为true时将命名空间前置到req.Topic,但BulkPublish方法未包含相同的命名空间前缀步骤。这导致批量发布的消息完全绕过了命名空间作用域。
解决方案
在publisher.go中的BulkPublish中,在作用域验证之后、在调用原生BulkPublisher或defaultBulkPublisher回退路径之前,添加了命名空间前缀守卫。这确保批量发布的消息与常规发布消息路由到相同的命名空间前缀主题。
在超时前接收到外部事件时,工作流计时器提醒未被删除
问题
当工作流使用带超时的WaitForSingleEvent时,会在调度器中创建一个计时器提醒。如果外部事件在计时器触发之前触发,则计时器提醒永远不会被删除,并作为孤儿保留在调度器中,直到最终不必要地触发。
此外,当工作流在计时器仍处于待处理状态时完成(例如尚未触发的CreateTimer),这些计时器提醒也会被遗留。
影响
使用带超时的WaitForSingleEvent的工作流在调度器中积累了孤儿计时器提醒。这些计时器最终会触发并触发不必要地工作流Actor调用,这些调用被静默忽略,浪费了调度器和Actor资源。
对于具有许多WaitForSingleEvent调用或长时间超时的长时间运行工作流,孤儿提醒的数量可能显著增长。
根因
持久任务SDK在接收到外部事件时完成事件任务,但不会通知Dapr运行时删除相关的计时器提醒。运行时没有机制检测计时器是否不再需要,因为其关联的事件已被接收。 类似地,当工作流完成时,没有清理尚未触发的待处理计时器提醒。
解决方案
向工作流编排器添加了两个计时器清理机制:
-
执行中清理(
deleteCancelledEventTimers):在每个工作流执行步骤之后,运行时扫描与WaitForSingleEvent调用关联的TimerCreated事件的历史记录(通过TimerCreated上的Name字段标识)。当在新的事件中找到匹配的EventRaised事件时,相应的计时器提醒从调度器中删除。事件名称匹配不区分大小写,并且已经删除的计时器(例如从崩溃恢复)通过忽略NotFound错误来优雅处理。 -
完成清理(
deleteAllReminders):当工作流完成且具有未触发的计时器(通过比较TimerCreated和TimerFired事件计数检测)时,通过DeleteByActorID批量删除工作流及其活动的所有提醒。这处理没有Name字段的计时器(例如CreateTimer),这些计时器无法与特定事件匹配。
Ollama会话组件规范中缺少端点元数据字段
问题
Ollama会话组件的元数据规范中缺少endpoint元数据字段,而该字段是配置Ollama服务器URL所必需的。
影响
配置Ollama会话组件的用户无法通过组件规范发现endpoint元数据字段。该字段在代码中是功能性的,但未在组件元数据规范中声明,使得依赖规范的工具和文档无法看到它。
根因
Ollama会话组件的metadata.yaml规范文件中省略了endpoint元数据字段。
解决方案
将endpoint元数据字段添加到Ollama会话组件规范(conversation/ollama/metadata.yaml)中。
使用MongoDB作为工作流Actor状态存储时,Dapr CLI无法列出工作流实例
问题
当MongoDB配置为工作流Actor状态存储时,Dapr CLI dapr workflow list命令失败。
影响
使用MongoDB作为工作流Actor状态存储的用户无法通过Dapr CLI列出工作流实例。列表操作需要基于前缀的键查询来枚举工作流实例,而MongoDB不支持此操作。
根因
MongoDB状态存储组件未实现KeysLiker接口,该接口提供基于前缀的键列表功能。Dapr CLI的工作流列表操作依赖此接口按前缀查询工作流实例键。
解决方案
在MongoDB状态存储组件上实现了KeysLiker接口,实现了Dapr CLI工作流列表命令所需的基于前缀的键列表查询。
LangChain Go Kit会话组件在未调用必需工具调用时不返回错误
问题
当LangChain Go Kit会话组件从LLM接收到包含必需工具调用的响应时,但这些工具调用未实际调用,未向调用者返回错误。
影响
使用基于LangChain Go Kit组件的会话API的应用程序可能在LLM请求未执行的工具调用时静默接收不完整的响应。调用者没有指示响应缺少预期的工具调用结果。
根因
LangChain Go Kit会话组件未检查LLM标记为必需的工具调用是否在对话轮次中被实际调用。
解决方案
添加了错误处理,以便在LLM响应包含未被调用的必需工具调用时返回错误,确保调用者被告知不完整的响应。
当颁发者密钥类型与CSR签名算法不匹配时,Sentry无法签署证书
问题
Sentry无法签署工作负载证书,错误如下:
x509:请求的SignatureAlgorithm与私钥类型不匹配
当CSR签名算法与颁发者密钥类型不匹配时会发生此情况。例如,当sidecar生成Ed25519 CSR但Sentry颁发者密钥为ECDSA时,或反之亦然。这破坏了sidecar和控制平面使用不同密钥类型的版本偏移场景。
影响
在版本偏移升级期间,当sidecar和Sentry使用不同的加密密钥类型时,sidecar无法从Sentry获取工作负载证书。所有mTLS保护的通信失败,阻止sidecar启动。
根因
Sentry将传入CSR上的SignatureAlgorithm复制到工作负载证书模板上。当调用x509.CreateCertificate时,Go的x509库拒绝模板签名算法(来自CSR)与颁发者私钥类型之间的不匹配。
解决方案
从证书模板和SignRequest结构体中移除了硬编码的SignatureAlgorithm。Go的x509.CreateCertificate现在从颁发者的签名密钥推断正确的签名算法,允许Sentry签署证书,而不管CSR的密钥类型如何。
更新内容 (原始)
Dapr 1.17.2
This update includes security fixes, a breaking change, a new component, and bug fixes:
- Go standard library vulnerabilities fixed by upgrading to Go 1.25.8
- Register RavenDB state store component
- Workflow state retention policy CRD fields use incorrect type (Breaking Change)
- Pub/sub messages incorrectly routed to dead-letter queue during graceful shutdown
- Scheduler jobs with Drop failure policy may fire more than once during host reconnection
- Scheduler fails to start due to trailing dot in cluster domain DNS lookup
- Service invocation buffers entire streaming request body in memory
- Service invocation buffers entire streaming response body in memory
- Oracle Database state store BulkGet returns HTTP 500 instead of per-key errors
- Pulsar pub/sub publishes invalid JSON messages when Avro schema is configured
- Actor placement dissemination failures with many replicas
- Nil pointer dereference in conversation LangChain Go Kit LLM logger
- Workflow activities with large results fail with gRPC ResourceExhausted error
- Bulk publish does not apply namespace prefix to topic
- Workflow timer reminders not deleted when external event is received before timeout
- Ollama conversation component missing endpoint metadata field in spec
- Dapr CLI cannot list workflow instances when using MongoDB as workflow actor state store
- LangChain Go Kit conversation component does not return error when required tool calls are not invoked
- Sentry fails to sign certificates when issuer key type does not match CSR signature algorithm
Go standard library vulnerabilities fixed by upgrading to Go 1.25.8
Problem
Three vulnerabilities were identified in the Go standard library used by Dapr 1.17.1 (Go 1.24.13):
- GO-2026-4603: URLs in meta content attribute actions are not escaped in
html/template, allowing potential cross-site scripting via crafted URLs. - GO-2026-4602:
FileInfocan escape from aRootinos, potentially allowing access to files outside an intended directory boundary. - GO-2026-4601: Incorrect parsing of IPv6 host literals in
net/url, which could lead to unexpected URL routing or SSRF in applications that parse user-supplied URLs.
Impact
Applications using html/template, os.Root-scoped file operations, or net/url URL parsing are potentially affected by these vulnerabilities. All three are fixed in Go 1.25.8.
Root Cause
The vulnerabilities are in the Go standard library and are not specific to Dapr code. They affect any Go program compiled with Go versions prior to 1.25.8.
Solution
Upgraded the Go toolchain from 1.24.13 to 1.25.8 across all modules and Docker images in the repository.
Register RavenDB state store component
Problem
The RavenDB state store component from components-contrib was not registered in the Dapr runtime, so it could not be used as a state store in Dapr applications.
Impact
Users could not use RavenDB as a state store backend with Dapr, despite the component implementation being available in components-contrib.
Root Cause
The component registration file for the RavenDB state store was missing from the Dapr runtime’s component loader (cmd/daprd/components/).
Solution
Added the state_ravendb.go registration file to register the RavenDB state store component with the default state store registry. The component is available when building with the allcomponents build tag. The ravendb-go-client dependency was added to go.mod.
Workflow state retention policy CRD fields use incorrect type (Breaking Change)
Problem
The Configuration CRD defined the stateRetentionPolicy fields (anyTerminal, completed, failed, terminated) as type: integer, format: int64, but the Go API types use metav1.Duration which serializes as strings (e.g. "1s", "168h").
This mismatch caused Kubernetes to reject valid duration string values for these fields, and prevented the workflow state retention policy from being configured correctly via the Kubernetes Configuration CRD.
Impact
Users running Dapr in Kubernetes mode could not configure the workflow state retention policy using the Configuration CRD with human-readable duration strings like "1s" or "168h". Kubernetes validation rejected these values because the CRD schema expected integers.
Additionally, even if integer nanosecond values were used to bypass the CRD schema validation, the internal configuration deserializer could not correctly unmarshal the metav1.Duration string format sent by the operator, causing daprd to fail with:
Fatal error from runtime: error loading configuration: json: cannot unmarshal string into Go struct field WorkflowStateRetentionPolicy.spec.workflow.stateRetentionPolicy.anyTerminal of type time.Duration
Root Cause
The Configuration CRD YAML (charts/dapr/crds/configuration.yaml) was not regenerated after the Go API type WorkflowStateRetentionPolicy was updated to use *metav1.Duration fields.
Solution
Updated the CRD schema to use type: string for all stateRetentionPolicy fields, matching the metav1.Duration serialization format.
Added a custom UnmarshalJSON method on the internal config.WorkflowStateRetentionPolicy struct that deserializes via the configapi.WorkflowStateRetentionPolicy type (which uses *metav1.Duration), correctly handling both the Kubernetes CRD string format and the standalone YAML format.
Upgrading
This is a change that requires a CRD update. Kubernetes does not automatically update CRDs when upgrading Dapr via Helm. You must manually update the CRDs before upgrading. See the Kubernetes upgrade guide for detailed instructions on how to force update CRDs.
To update CRDs manually:
kubectl apply -f https://raw.githubusercontent.com/dapr/dapr/v1.17.2/charts/dapr/crds/configuration.yaml
Pub/sub messages incorrectly routed to dead-letter queue during graceful shutdown
Problem
During graceful shutdown (or hot-reload of a pub/sub component), messages arriving after the subscription began closing were immediately NACKed by Dapr. Brokers that support dead-letter queues interpreted these NACKs as permanent delivery failures and routed the messages to the dead-letter queue, where they were never retried.
Impact
Applications using pub/sub with dead-letter queues configured could lose messages during rolling deployments, restarts, or any event that triggers graceful shutdown. Rather than being redelivered to another healthy consumer, these messages were silently diverted to the dead-letter queue. This affected all subscription types: declarative, programmatic (HTTP and gRPC), and streaming subscriptions.
Root Cause
When a subscription was closing, Dapr rejected new incoming messages with a “subscription is closed” error. The pluggable pub/sub component layer translated this error into a NACK sent back to the broker. The broker then treated the message as a permanent failure and routed it to the configured dead-letter topic.
Solution
Dapr now holds messages that arrive during subscription shutdown instead of rejecting them. The message handler blocks until the broker connection is torn down, at which point the broker treats the message as unacknowledged and redelivers it to another available consumer. In-flight messages that were already being processed continue to complete normally before the subscription fully closes.
Scheduler jobs with Drop failure policy may fire more than once during host reconnection
Problem
When the scheduler cluster membership changed (including during initial startup), one-shot jobs or jobs with a Drop failure policy could be triggered more than once.
Impact
Jobs configured with DueTime (one-shot) or a Drop failure policy could be delivered to the application multiple times instead of at most once.
This was more likely to occur during scheduler startup or when the scheduler cluster membership changed, as etcd can emit multiple membership events in quick succession.
Root Cause
A race condition existed between two asynchronous event loops in daprd’s scheduler connection management. The hosts loop manages gRPC client connections to the scheduler, and the connector loop manages the stream-based cluster that runs on those connections.
When the hosts loop received a second set of scheduler host addresses (e.g. from an etcd membership event during startup), it immediately closed the first set of gRPC client connections before the connector loop had a chance to gracefully stop the cluster running on those connections. This caused active streams to break mid-flight, in-flight job triggers to be marked as undeliverable and re-staged, and jobs to fire again when new streams connected.
Solution
Moved gRPC connection lifecycle management from the hosts loop to the connector loop.
The hosts loop now passes connection close functions to the connector via the Connect event, and the connector closes old connections only after it has gracefully stopped the previous cluster.
This ensures connections are never closed while streams are still active.
Scheduler fails to start due to trailing dot in cluster domain DNS lookup
Problem
The Dapr Scheduler service fails to start in Kubernetes with a fatal error:
Fatal error running scheduler: failed to create etcd config: peer certificate does not contain the expected DNS name dapr-scheduler-server-1.dapr-scheduler-server.dapr-system.svc.cluster.local. got [dapr-scheduler-server-0.dapr-scheduler-server.dapr-system.svc.cluster.local dapr-scheduler-server-1.dapr-scheduler-server.dapr-system.svc.cluster.local dapr-scheduler-server-2.dapr-scheduler-server.dapr-system.svc.cluster.local]
Impact
The Scheduler service cannot start in any Kubernetes cluster where the DNS CNAME lookup for the cluster domain returns a fully-qualified domain name with a trailing dot (standard DNS behavior). This prevents all scheduler-based functionality including job scheduling.
Root Cause
The scheduler resolves the Kubernetes cluster domain via a DNS CNAME lookup. Per DNS convention, CNAME responses include a trailing dot (e.g. cluster.local.).
The code only stripped leading dots from the result, leaving the trailing dot intact.
This caused the etcd peer TLS server name to end with an extra dot, which did not match the certificate SANs and failed validation.
Solution
Changed strings.TrimLeft to strings.Trim to strip dots from both ends of the parsed cluster domain, ensuring the trailing dot from DNS CNAME responses is removed.
Service invocation buffers entire streaming request body in memory
Problem
When sending a request with a streaming body (chunked transfer encoding) through Dapr HTTP service invocation, the sidecar buffered the entire request body in memory before forwarding it. For large payloads—such as file uploads or long-running data streams—this caused excessive memory usage and potential out-of-memory crashes.
Impact
Any HTTP service invocation request without a known Content-Length (e.g. chunked uploads, streamed data, piped bodies) had its entire body buffered in memory by the sending sidecar.
This made Dapr unsuitable for streaming large payloads between services and could cause sidecar OOM kills in production.
Root Cause
The sidecar’s retry mechanism unconditionally buffered the request body into memory so it could replay the body on retry. For streaming requests, the body cannot be replayed because it is consumed as it is read, making the buffering both unnecessary and harmful.
Solution
The sidecar now detects streaming requests (those with no known content length) and skips request body buffering entirely.
Both the built-in retry logic and any user-configured resiliency retry policies are automatically bypassed for streaming requests, since retrying would require re-reading a body that has already been consumed.
Non-streaming requests with a known Content-Length continue to support retries as before.
Service invocation buffers entire streaming response body in memory
Problem
When proxying HTTP responses through service invocation, the sidecar buffered the entire response body in memory before forwarding it to the caller. For large or unbounded streaming responses, this caused excessive memory usage and potential out-of-memory crashes.
Impact
Any service invocation response with a large or streaming body could cause sidecar OOM kills, regardless of HTTP status code. This made Dapr unsuitable for proxying streaming responses such as server-sent events, file downloads, or long-running data streams between services.
Root Cause
The sidecar’s resiliency mechanism read the full response body into memory so it could evaluate whether to retry the request. When the request itself is a stream that has already been consumed, retries are impossible regardless of the response, making the buffering unnecessary.
Solution
For streaming requests, the sidecar now forwards response bodies directly to the caller without buffering them in memory. Resiliency features like circuit breakers continue to track failures normally. Non-streaming requests continue to support retries and buffered error handling as before.
Oracle Database state store BulkGet returns HTTP 500 instead of per-key errors
Problem
When using the Oracle Database state store component, a BulkGet request that encountered an error for one or more keys returned an HTTP 500 error for the entire request instead of returning per-key errors alongside successful results.
Impact
Applications using BulkGet with the Oracle Database state store could not retrieve any results if even a single key encountered an error. Instead of receiving successful results for valid keys with per-key errors for failed keys, the entire operation failed with an HTTP 500 response.
Root Cause
The BulkGet implementation in the Oracle Database state store component returned a top-level error when any individual key retrieval failed, rather than collecting the error and associating it with the specific key in the response.
Solution
Updated the BulkGet implementation to return per-key errors in the BulkGetResponse items instead of returning a top-level error. Successful key retrievals are now returned alongside any per-key errors, matching the expected state store BulkGet contract.
Pulsar pub/sub publishes invalid JSON messages when Avro schema is configured
Problem
When the Pulsar pub/sub component was configured with an Avro schema, JSON messages were published without being validated against the schema. Invalid messages that did not conform to the Avro schema were accepted and published to the topic.
Impact
Applications relying on Avro schema enforcement at the Pulsar pub/sub layer could publish malformed messages that did not conform to the expected schema. Downstream consumers expecting schema-compliant messages could encounter deserialization failures or data integrity issues.
Root Cause
The Pulsar pub/sub component did not validate JSON message payloads against the configured Avro schema before publishing. The schema was used only for consumer-side deserialization, not for producer-side validation.
Solution
Added JSON-to-Avro schema validation in the publish path. Before publishing, the component now validates JSON message payloads against the configured Avro schema and returns an error if the message does not conform, preventing invalid messages from being published to the topic.
Actor placement dissemination failures with many replicas
Problem
After upgrading to Dapr 1.17.x, deployments with many replicas (e.g. 50+) experience frequent “dissemination timeout after 8s” errors, and /placement/state showing only a fraction of expected hosts.
Impact
Actor invocations fail intermittently because most sidecars never receive a complete placement table. Rolling restarts and scaling events amplify the problem, making large actor deployments unstable.
Root Cause
Three issues combined to cause a cascading failure during dissemination:
- Stale UNLOCK version accepted: The sidecar disseminator assigned the incoming version before comparing it against the current version, so the guard
currentVersion > versionalways evaluated to false. Stale UNLOCK messages were incorrectly applied. - Errors killed the disseminator permanently: When the sidecar detected a version mismatch on UPDATE or received an unknown operation, it returned a fatal error that terminated the disseminator loop entirely. The sidecar never reconnected to the placement service and remained stuck.
- Sequential dissemination rounds for concurrent connections: When many replicas connected to the placement service simultaneously while a dissemination round was in progress, each waiting connection triggered its own sequential dissemination round on completion. With N waiting replicas, this created N rounds instead of 1, causing timeouts that disconnected other sidecars and produced the cascading failure.
Solution
- Fixed the UNLOCK version guard to compare before assignment, so stale versions are correctly rejected.
- Changed version mismatch and unknown operation handling to cancel the stream and trigger a clean reconnection instead of killing the disseminator.
- Batched all connections that arrive during an active dissemination round into a single round, reducing N sequential rounds to 1.
Nil pointer dereference in conversation LangChain Go Kit LLM logger
Problem
The conversation component using the LangChain Go Kit could panic with a nil pointer dereference when the LLM logger was invoked.
Impact
Applications using the conversation API with the LangChain Go Kit-based component could experience unexpected crashes due to a nil pointer dereference, causing the Dapr sidecar to restart.
Root Cause
The LLM logger callback in the LangChain Go Kit conversation component was called with a nil pointer, and the logger did not perform a nil check before accessing the pointer.
Solution
Added a nil pointer check in the LangChain Go Kit LLM logger to prevent the dereference, ensuring the conversation component handles the case gracefully without panicking.
Workflow activities with large results fail with gRPC ResourceExhausted error
Problem
Workflow activities that return results larger than ~2MB fail with a ResourceExhausted gRPC error when scheduling the activity result reminder via the scheduler:
Error scheduling reminder job activity-result-XXXX due to: rpc error: code = ResourceExhausted desc = trying to send message larger than max (37950104 vs. 2097152)
Impact
Any workflow activity returning a result larger than the default gRPC send message size limit (~2MB) fails to deliver its result back to the parent orchestration. The orchestration hangs indefinitely waiting for the activity result, eventually timing out or stalling.
Root Cause
The scheduler gRPC client configured MaxCallRecvMsgSize to allow receiving large messages, but did not configure MaxCallSendMsgSize. This left the send-side limit at the gRPC default (~2MB). When an activity completes, its result is serialized into a reminder job request sent to the scheduler. If the activity result exceeds the default limit, the gRPC client rejects the outgoing message before it reaches the server.
Solution
Added MaxCallSendMsgSize to the scheduler gRPC client dial options, matching the existing MaxCallRecvMsgSize configuration.
Bulk publish does not apply namespace prefix to topic
Problem
When using the Bulk Publish API with a pub/sub component that has NamespaceScoped enabled, messages were published to the un-namespaced topic instead of the namespace-prefixed topic.
Impact
Applications using namespace-scoped pub/sub components with the Bulk Publish API experienced silent message loss. Bulk-published messages were routed to the wrong topic (e.g. the un-namespaced exchange), while subscribers were listening on the namespace-prefixed topic. The regular Publish API was not affected, so only bulk publish users encountered this issue.
Root Cause
The Publish method in publisher.go prepends the namespace to req.Topic when NamespaceScoped is true, but the BulkPublish method did not include this same namespace-prefixing step. This caused bulk-published messages to bypass the namespace scoping entirely.
Solution
Added the namespace prefix guard to BulkPublish in publisher.go, immediately after scope validation and before either the native BulkPublisher or defaultBulkPublisher fallback path is invoked. This ensures bulk-published messages are routed to the same namespace-prefixed topic as regular published messages.
Workflow timer reminders not deleted when external event is received before timeout
Problem
When a workflow used WaitForSingleEvent with a timeout, a timer reminder was created in the scheduler. If the external event was raised before the timer fired, the timer reminder was never deleted and remained as an orphan in the scheduler until it eventually fired unnecessarily.
Additionally, when a workflow completed while timers were still pending (e.g. a CreateTimer that had not yet fired), those timer reminders were also left behind.
Impact
Workflows using WaitForSingleEvent with timeouts accumulated orphan timer reminders in the scheduler. These timers would eventually fire and trigger unnecessary workflow actor invocations that were silently ignored, wasting scheduler and actor resources.
For long-running workflows with many WaitForSingleEvent calls or long timeouts, the number of orphan reminders could grow significantly.
Root Cause
The durable task SDK completes the event task when an external event is received, but does not signal the Dapr runtime to delete the associated timer reminder. The runtime had no mechanism to detect that a timer was no longer needed because its associated event had already been received. Similarly, when a workflow completed, there was no cleanup of pending timer reminders that had not yet fired.
Solution
Added two timer cleanup mechanisms to the workflow orchestrator:
-
Mid-execution cleanup (
deleteCancelledEventTimers): After each workflow execution step, the runtime scans the history forTimerCreatedevents associated withWaitForSingleEventcalls (identified by theNamefield onTimerCreated). When a matchingEventRaisedevent is found in the new events, the corresponding timer reminder is deleted from the scheduler. Event name matching is case-insensitive, and already-deleted timers (e.g. from a crash recovery) are handled gracefully by ignoringNotFounderrors. -
Completion cleanup (
deleteAllReminders): When a workflow completes and has unfired timers (detected by comparingTimerCreatedvsTimerFiredevent counts), all reminders for the workflow and its activities are bulk-deleted viaDeleteByActorID. This handles timers without aNamefield (e.g.CreateTimer) that cannot be matched to specific events.
Ollama conversation component missing endpoint metadata field in spec
Problem
The Ollama conversation component’s metadata spec was missing the endpoint metadata field, which is required to configure the Ollama server URL.
Impact
Users configuring the Ollama conversation component could not discover the endpoint metadata field through the component spec. The field was functional in code but not declared in the component metadata spec, making it invisible to tooling and documentation that relies on the spec.
Root Cause
The endpoint metadata field was omitted from the Ollama conversation component’s metadata.yaml spec file.
Solution
Added the endpoint metadata field to the Ollama conversation component spec (conversation/ollama/metadata.yaml).
Dapr CLI cannot list workflow instances when using MongoDB as workflow actor state store
Problem
The Dapr CLI dapr workflow list command failed when MongoDB was configured as the workflow actor state store.
Impact
Users using MongoDB as their workflow actor state store could not list workflow instances via the Dapr CLI. The list operation requires prefix-based key queries to enumerate workflow instances, which MongoDB did not support.
Root Cause
The MongoDB state store component did not implement the KeysLiker interface, which provides prefix-based key listing functionality. The Dapr CLI’s workflow list operation depends on this interface to query workflow instance keys by prefix.
Solution
Implemented the KeysLiker interface on the MongoDB state store component, enabling the prefix-based key listing queries required by the Dapr CLI workflow list command.
LangChain Go Kit conversation component does not return error when required tool calls are not invoked
Problem
When the LangChain Go Kit conversation component received a response from the LLM that included required tool calls, but those tool calls were not actually invoked, no error was returned to the caller.
Impact
Applications using the conversation API with the LangChain Go Kit component could silently receive incomplete responses when the LLM requested tool calls that were not executed. The caller had no indication that the response was missing expected tool call results.
Root Cause
The LangChain Go Kit conversation component did not check whether tool calls flagged as required by the LLM were actually invoked during the conversation turn.
Solution
Added error handling to return an error when the LLM response includes required tool calls that were not invoked, ensuring the caller is informed of the incomplete response.
Sentry fails to sign certificates when issuer key type does not match CSR signature algorithm
Problem
Sentry fails to sign workload certificates with the error:
x509: requested SignatureAlgorithm does not match private key type
This occurs when the CSR signature algorithm does not match the issuer key type. For example, when a sidecar generates an Ed25519 CSR but the Sentry issuer key is ECDSA, or vice versa. This breaks version skew scenarios where the sidecar and control plane use different key types.
Impact
Sidecars cannot obtain workload certificates from Sentry during version skew upgrades where the sidecar and Sentry use different cryptographic key types. All mTLS-secured communication fails, preventing the sidecar from starting.
Root Cause
Sentry copied the SignatureAlgorithm from the incoming CSR onto the workload certificate template. When x509.CreateCertificate was called, Go’s x509 library rejected the mismatch between the template’s signature algorithm (from the CSR) and the issuer’s private key type.
Solution
Removed the hardcoded SignatureAlgorithm from certificate templates and the SignRequest struct. Go’s x509.CreateCertificate now infers the correct signature algorithm from the issuer’s signing key, allowing Sentry to sign certificates regardless of the CSR’s key type.
下载链接
- daprd_darwin_amd64.tar.gz
- daprd_darwin_amd64.tar.gz.sha256
- daprd_darwin_arm64.tar.gz
- daprd_darwin_arm64.tar.gz.sha256
- daprd_linux_amd64-stablecomponents.tar.gz
- daprd_linux_amd64-stablecomponents.tar.gz.sha256
- daprd_linux_amd64.tar.gz
- daprd_linux_amd64.tar.gz.sha256
- daprd_linux_arm-stablecomponents.tar.gz
- daprd_linux_arm-stablecomponents.tar.gz.sha256
- daprd_linux_arm.tar.gz
- daprd_linux_arm.tar.gz.sha256
- daprd_linux_arm64-stablecomponents.tar.gz
- daprd_linux_arm64-stablecomponents.tar.gz.sha256
- daprd_linux_arm64.tar.gz
- daprd_linux_arm64.tar.gz.sha256
- daprd_windows_amd64.zip
- daprd_windows_amd64.zip.sha256
- grafana-actor-dashboard.json
- grafana-actor-dashboard.json.sha256
- grafana-sidecar-dashboard.json
- grafana-sidecar-dashboard.json.sha256
- grafana-system-services-dashboard.json
- grafana-system-services-dashboard.json.sha256
- injector_darwin_amd64.tar.gz
- injector_darwin_amd64.tar.gz.sha256
- injector_darwin_arm64.tar.gz
- injector_darwin_arm64.tar.gz.sha256
- injector_linux_amd64.tar.gz
- injector_linux_amd64.tar.gz.sha256
- injector_linux_arm.tar.gz
- injector_linux_arm.tar.gz.sha256
- injector_linux_arm64.tar.gz
- injector_linux_arm64.tar.gz.sha256
- injector_windows_amd64.zip
- injector_windows_amd64.zip.sha256
- operator_darwin_amd64.tar.gz
- operator_darwin_amd64.tar.gz.sha256
- operator_darwin_arm64.tar.gz
- operator_darwin_arm64.tar.gz.sha256
- operator_linux_amd64.tar.gz
- operator_linux_amd64.tar.gz.sha256
- operator_linux_arm.tar.gz
- operator_linux_arm.tar.gz.sha256
- operator_linux_arm64.tar.gz
- operator_linux_arm64.tar.gz.sha256
- operator_windows_amd64.zip
- operator_windows_amd64.zip.sha256
- placement_darwin_amd64.tar.gz
- placement_darwin_amd64.tar.gz.sha256
- placement_darwin_arm64.tar.gz
- placement_darwin_arm64.tar.gz.sha256
- placement_linux_amd64.tar.gz
- placement_linux_amd64.tar.gz.sha256
- placement_linux_arm.tar.gz
- placement_linux_arm.tar.gz.sha256
- placement_linux_arm64.tar.gz
- placement_linux_arm64.tar.gz.sha256
- placement_windows_amd64.zip
- placement_windows_amd64.zip.sha256
- scheduler_darwin_amd64.tar.gz
- scheduler_darwin_amd64.tar.gz.sha256
- scheduler_darwin_arm64.tar.gz
- scheduler_darwin_arm64.tar.gz.sha256
- scheduler_linux_amd64.tar.gz
- scheduler_linux_amd64.tar.gz.sha256
- scheduler_linux_arm.tar.gz
- scheduler_linux_arm.tar.gz.sha256
- scheduler_linux_arm64.tar.gz
- scheduler_linux_arm64.tar.gz.sha256
- scheduler_windows_amd64.zip
- scheduler_windows_amd64.zip.sha256
- sentry_darwin_amd64.tar.gz
- sentry_darwin_amd64.tar.gz.sha256
- sentry_darwin_arm64.tar.gz
- sentry_darwin_arm64.tar.gz.sha256
- sentry_linux_amd64.tar.gz
- sentry_linux_amd64.tar.gz.sha256
- sentry_linux_arm.tar.gz
- sentry_linux_arm.tar.gz.sha256
- sentry_linux_arm64.tar.gz
- sentry_linux_arm64.tar.gz.sha256
- sentry_windows_amd64.zip
- sentry_windows_amd64.zip.sha256