Repository navigation
Error: cannot get required service "sessionProjections" in inactive context after running several tasks
#10272
Replies: 1 comment
|
The line you found is the right one, and the mechanics around it explain the part of the symptom that looks like a bug in the service.
let fiber = (ctx[symbols.shadow] as Context ?? ctx).fiber
while (true) {
const impl = fiber.store?.[prop]
if (impl) return getTraceable(ctx, impl.value)
if (prop in fiber.inject) {
error.message = `cannot get required service "${prop}" in inactive context`
throw error
}
if (!fiber.runtime) throw error
if (fiber.parent[symbols.isolate][prop] !== key) throw error
fiber = fiber.parent.fiber
}The important detail is the ordering. The service store is only populated while a fiber is loaded, so for an inactive fiber It also explains the spread you describe. One retained context from a torn-down scope is enough: every later read through it throws, and tool calls all go through that scope, so one stale reference looks like a whole-session failure while a fresh session works. Two cautions for the write-up. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Here comes a fatal problem to me. Have other users found similiar problems? The issue is summarized by DSH.
Bug:
Error: cannot get required service "sessionProjections" in inactive contextafter running several tasks环境 / Environment
0.2.1-rc.2(@deepseek-ai/dsh-desktop-runtime,见package.json的version字段,所有@deepseek-ai/dsh-*/@deepseek-ai/cordis依赖均为该 RC 版本)@deepseek-ai/dsh-agent-loop0.2.1-rc.2@deepseek-ai/dsh-session-projection0.2.1-rc.2@deepseek-ai/cordis4.0.5(vendor,反射/注入层)resources/app.asar打包)read/bash/glob/working_directory),导致整个会话瘫痪,只能靠新建会话恢复 active context。复现步骤 / Reproduction
在 DSH 中连续发起多个并行/串行任务(subagent、background job、workflow 等)。
让部分任务(子 agent / scope)完成并进入 teardown,同时其他任务继续运行,制造频繁的 scope 创建 / 销毁。
观察数分钟到数十分钟后,随机一次工具调用或 loop 内部访问抛:
此后该会话的所有工具调用持续返回同一错误,直到新建会话。
错误源码定位 / Root-cause source trace
1. 错误抛出点(Cordis 反射/注入层)
jsonl/lib/worker.cjs(即vendor/cordis/src/reflect.ts的编译产物):含义:组件在
inject中声明了sessionProjections,但读取时所在的 fiber / context 已被 dispose(状态INACTIVE/__INACTIVE__,见worker.cjs:1963、_setEpoch(INACTIVE))。 Cordis 会沿父级 fiber 向上查找,但路径上第一个命中inject且已 inactive 的就直接抛错,不会回落到仍存活的父级运行时。相关常量:INACTIVE_EFFECT(worker.cjs:1961)、INACTIVE = "__INACTIVE__"(worker.cjs:1963)。2. 服务定义
@deepseek-ai/dsh-session-projection/lib/index.js:SessionProjectionRegistry extends Service,以super(ctx, "sessionProjections")注册在根 app 上下文,承载每会话的投影状态(inbox、turnBoundary、runtimeContext 等),通过session/event订阅做 eager drive。3. 触发点(消费方)
@deepseek-ai/dsh-agent-loop/lib/index.js:createScope(loopCtx, this)建子 scope 上下文,this.ctx = this.scope.ctx(:778-779)。this.ctx.sessionProjections访问投影服务(绑定在子 scope 上):new ReactLoopInbox(this.ctx.sessionProjections, session, this.dispatch)(:780)this.loopCtx.sessionProjections.stateOf(session, "turnBoundary")(:782)ctx.effect(function*(){ const unregisterTurnBoundary = ctx.sessionProjections.register(...); ... })(:1580-1589),disposer 绑在 fiber 上。根因:scope 被 dispose 之后,仍有延迟执行逻辑(inbox 变更、
turnBoundary更新、change-feed 监听回调、ownershipteardown 回调等)继续用this.ctx.sessionProjections(已死 scope)去读投影服务。第一次在 dispose 后触发的访问即抛 "in inactive context"。任务越多、scope 生灭越频繁,撞上失效访问的概率越高 → "跑一阵就全挂"。佐证:同文件
ReactLoopInbox.current()已写过正确的同类守卫且多处已有
if (!this.ownership.isActive()) return;(:1625/:1643/:1651/:2009)的 active 守卫惯例——但投影访问路径未全覆盖。建议修复 / Suggested fixes
临时规避(用户侧)
maxParallelToolCalls默认 10(:1554),压低并行 subagent / background job 数量。job_kill或等子任务回写完成,避免它们在会话失活后回碰会话级服务。代码层根治(维护者侧,按优先级)
ReactLoopInbox调用时不要持有this.ctx.sessionProjections(子 scope,随 dispose 失效),改为捕获并保持this.loopCtx.sessionProjections(根/loop 上下文,不受子 scope dispose 影响)。if (!this.ownership.isActive()) return;/ 检查fiber.runtime,把失效访问在用户态短路,而非交给 Cordis 抛底层错。SessionProjectionRegistry.listeners(全局Set)注册了 change-feed 监听的 scope 一旦 dispose,其回调若仍引用失效 session/scope 会回调进死 ctx;确保 scope 卸载时从listeners移除回调。ctx.effect中unregisterInbox/TurnBoundary(:1585-1588)在 scope dispose 后才执行,期间其他组件读该 key 会命中 "registration not active";让stateOf/ 读取侧在注册已卸时安全降级(参考既有state === void 0守卫),而非抛错中断整个 loop。ReflectService.handler.get中,当本 fiber inactive 但父级仍有 live 运行时提供该服务时回落到父级——会改变注入语义,风险高,优先在用法侧(1–4)修。补充 / Notes
C:/Users/15940/Documents/deepseek-harness/default-workspace/_work/pkg/(dsh-agent-loop、dsh-session-projection、jsonl等),与resources/app.asar内0.2.1-rc.2一致。All reactions