Skip to content

finding(service-automation): connector 物化失败的 fail() 也是 ${err.message} 单行插值,同 #5048 的类别、另一个接缝 #5575

Description

@os-zhuang

#5048(PR #5572)时在同包扫到的同类形态,按 Prime Directive #10 单开,不在那个 PR 里扩面。

现象

AutomationServicePlugin.materializeDeclaredConnectors 的报错器(packages/services/service-automation/src/plugin.ts:1039)在软路径上把消息字符串交给 logger:

// Report a reconcile problem: fatal (boot) throws; soft (reload) logs.
const fail = (msg: string): void => {
    if (opts.fatal) throw new Error(msg);
    ctx.logger.error(msg);
};

而两个调用点把底层错误的 message 插进那个字符串:

  • plugin.ts:1122resolveInstanceAuth 失败:fail((err as Error).message)
  • plugin.ts:1158-1161 — provider factory 抛错:fail(`[Automation] failed to materialize connector instance '${name}' via provider '${provider}': ${(err as Error).message} (ADR-0097).`)

这与 #5048 修掉的形态一模一样:err.message 一旦是多行(ZodError 的 .message 是 issue 数组的 JSON dump,第一行就是一个 [),ObjectLogger.write() 只有第一行带等级前缀,而 serveBootLogCapture.offer() 逐行过滤、把没有前缀的续行全部丢弃 —— 诊断退化成一个 [

fatal: true 那条路(冷启动)不受影响:它 throw,走 kernel 的失败通道,不经过启动诊断缓冲。受影响的是软路径,即 metadata:reloaded 之后的重新物化 —— 也就是 Studio publish / os dev 重编译之后。

可达性:今天大概到不了,所以是 finding

我查过 packages/connectors/*/src(openapi / mcp / rest / slack),目前没有 provider factory 做 Zod .parse()(只有 openapi 的一处 JSON.parse),所以今天从 factory 抛出 ZodError 的路径我没能证明存在。resolveInstanceAuth 那条也没查到 Zod 解析。

但这个形态的风险不需要 ZodError 才成立:任何多行 err.message 都会被同一台管线截断,而 ADR-0097 明确鼓励第三方写 provider factory —— 第一个在 factory 里用 Zod 校验 providerConfig 的插件(这是很自然的写法)就会撞上。而且撞上时的症状和 cloud#971 一样:症状不可读,所以缺陷得以隐身

建议的修法

与 PR #5572 同一原则,复用它落地的 helper:

const fail = (msg: string, cause?: unknown): void => {
    if (opts.fatal) throw new Error(msg);
    ctx.logger.error(msg, cause === undefined ? undefined : describeFlowBindError(cause));
};

(describeFlowBindErrorpackages/services/service-automation/src/flow-bind-diagnostics.ts,PR #5572 引入;若要给 connector 复用,名字值得从 FlowBind* 泛化成 describeThrownForLog 一类,那是这单要顺带定的一个小决定。注意 Logger.error 的签名是 error(message, error?: Error, meta?) —— 第二参是 Error 不是 meta,ObjectLogger.error 在运行时对二者都做了分派,但类型上要走 meta 就得确认契约,不能想当然。)

影响面


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions