
Dagger TypeScript SDK 错误处理详解ExecError 类的属性、源码与实战捕获【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger本篇技术指南以 Dagger TypeScript SDK 中ExecError类API 参考见 ExecError.md为核心介绍当容器流水线pipeline中的exec操作失败时SDK 如何把底层命令退出信息包装成可编程处理的错误对象。读完本文你将掌握ExecError的全部属性语义、错误码D109的含义、SDK 内部抛出该错误的底层机制以及如何在 TypeScript 项目中精准捕获并诊断容器命令执行失败。ExecError 是什么流水线 exec 操作的 API 错误在 Dagger 中构建、测试、发布任何代码库的核心动作大多是对容器执行命令withExec当某个容器命令以非零退出码结束Dagger 引擎会将其标记为EXEC_ERROR类型Dagger TypeScript SDK 在收到该 GraphQL 响应后会抛出ExecError。从类型体系上看ExecError直接继承自抽象基类DaggerSDKError后者是所有 Dagger 错误的父类基类定义了name与code两个抽象只读属性要求每个子类提供 Dagger 专属的错误名称与错误码基类持有cause引发错误的原始 Error、message与stack基类还提供printStackTrace()方法用于将堆栈打印到控制台源码见 DaggerSDKError.ts。ExecError的定义位于 ExecError.ts其类签名与构造函数如下export class ExecError extends DaggerSDKError { name ERROR_NAMES.ExecError code ERROR_CODES.ExecError cmd: string[] exitCode: number stdout: string stderr: string extensions?: GraphQLErrorExtensions constructor(message: string, options: ExecErrorOptions) { super(message, options) this.cmd options.cmd this.exitCode options.exitCode this.stdout options.stdout this.stderr options.stderr this.extensions options.extensions } }其中ExecErrorOptions在DaggerSDKErrorOptions仅含cause基础上要求调用方必须提供cmd、exitCode、stdout、stderr并可附带 GraphQL 扩展信息extensions。属性全解从命令到输出的完整诊断信息ExecError携带了排障所需的全部现场信息每个字段都与一次失败的 exec 操作一一对应。cmd导致错误的命令cmd: string[]以字符串数组形式保存触发出错的完整命令及其参数例如[sh, -c, cat /testout 1; cat /testerr 2; exit 127]。注意它是参数数组而非拼接好的单行字符串便于你直接在错误处理中重建命令或做日志脱敏。exitCode命令退出码exitCode: number容器内命令的退出码。非零退出码如127表示命令不存在、1表示通用运行失败是 exec 报错的直接原因。在 SDK 内部当引擎未提供该字段时会回退为-1。stdout 与 stderr标准输出与标准错误stdout: string stderr: string命令执行期间产生的标准输出与标准错误内容是定位问题最直接的日志来源。在 SDK 实现中若引擎未返回对应字段会回退为空字符串。值得注意的一个细节stdout/stderr不会混入message测试用例专门断言了e.toString()与e.message均不包含 stdout/stderr 内容见 api.spec.ts因此你可以安全地把message作为简短摘要展示而把完整输出单独记录。extensionsGraphQL 错误扩展信息extensions?: any透传 GraphQL 响应中附带的extensions对象。SDK 正是通过其中的_type EXEC_ERROR来识别 exec 失败并构造ExecError的详见下文“源码机制”一节。name、code、cause、message、stack属性类型说明来源nameExecErrorDagger 错误名称值来自ERROR_NAMES.ExecError覆盖基类codeD109Dagger 专属错误码值来自ERROR_CODES.ExecError覆盖基类causeError可选引发错误的原始 Error 对象继承自DaggerSDKErrormessagestring错误摘要信息继承自Errorstackstring可选调用堆栈继承自Error方法printStackTrace()printStackTrace(): void继承自DaggerSDKError调用内部日志工具打印this.stack见 DaggerSDKError.ts适合在 catch 分支中快速输出堆栈定位调用链。错误码体系D109 在整个 Dagger 错误表中的位置Dagger TypeScript SDK 为每一类错误分配了稳定的字符串错误码便于程序化区分错误类型统一定义在 errors-codes.ts错误码错误类D100GraphQLRequestErrorD101UnknownDaggerErrorD102TooManyNestedObjectsErrorD103EngineSessionConnectParamsParseErrorD104EngineSessionConnectionTimeoutErrorD105EngineSessionErrorD106InitEngineSessionBinaryErrorD107DockerImageRefValidationErrorD108NotAwaitedRequestErrorD109ExecErrorD110IntrospectionErrorExecError的name与code均在类初始化时通过ERROR_NAMES.ExecError、ERROR_CODES.ExecError赋值因此每个实例天然携带D109标识。所有错误类统一从 index.ts 导出你可以用以下方式按错误码或错误类型做分支处理import { ExecError, ERROR_CODES } from dagger.io/dagger catch (e) { if (e instanceof ExecError) { console.error(Dagger exec failed with code ${e.code}) // D109 } // 或按错误码判断 if ((e as any).code ERROR_CODES.ExecError) { /* ... */ } }源码机制ExecError 是在哪里被抛出的ExecError并非在容器执行现场直接抛出而是由 SDK 的 GraphQL 查询层在收到引擎错误响应后统一构造。关键调用链位于 compute_query.ts 的compute函数} catch (e: any) { if (e instanceof ClientError) { const msg e.response.errors?.[0]?.message ?? API Error const ext e.response.errors?.[0]?.extensions if (ext?._type EXEC_ERROR) { throw new ExecError(msg, { cmd: (ext.cmd as string[]) ?? [], exitCode: (ext.exitCode as number) ?? -1, stdout: (ext.stdout as string) ?? , stderr: (ext.stderr as string) ?? , extensions: ext, }) } throw new GraphQLRequestError(msg, { error: e, cause: e }) } // ... }机制要点SDK 通过 GraphQL 客户端请求引擎若返回ClientError则读取首个 GraphQL error 的message与extensions当extensions._type EXEC_ERROR时从扩展字段中提取cmd、exitCode、stdout、stderr并构造ExecError抛出——这就是实例属性与 GraphQL 扩展字段的对应来源若错误类型不是 exec 失败则回退抛出GraphQLRequestError连接被拒ECONNREFUSED时抛出NotAwaitedRequestError提示函数未被await其余情况抛出UnknownDaggerError。这一设计意味着凡是容器内命令执行失败例如withExec后调用sync()你捕获到的几乎都是ExecError且其cmd、exitCode、stdout、stderr字段与引擎返回一一对应。实战捕获从测试用例看正确的处理姿势官方测试 api.spec.ts 中“Return custom ExecError”用例演示了完整的触发与校验流程const stdout STDOUT HERE const stderr STDERR HERE const args [sh, -c, cat /testout 1; cat /testerr 2; exit 127] await connect(async (client: Client) { const ctr client .container() .from(alpine:3.16.2) .withDirectory(/, client.directory() .withNewFile(testout, stdout) .withNewFile(testerr, stderr)) .withExec(args) try { await ctr.sync() } catch (e) { if (e instanceof ExecError) { assert(e.message.includes(exit code: 127)) assert.strictEqual(e.exitCode, 127) assert.strictEqual(e.stdout, stdout) assert.strictEqual(e.stderr, stderr) assert(!e.toString().includes(stdout)) assert(!e.message.includes(stderr)) } else { throw e } } })由该用例可提炼出三条实战经验捕获方式优先使用e instanceof ExecError做类型守卫避免用any断言丢失类型信息sync()是触发容器真正执行的入口错误在此处抛出信息一致性exitCode、stdout、stderr与容器内真实行为完全一致可直接作为 CI 失败诊断的依据message中会包含类似exit code: 127的摘要但不会混入完整 stdout/stderr适合展示给用户未命中的兜底如果 exec 失败但捕获到的不是ExecError例如请求层异常应重新抛出或记录原始错误避免吞掉异常。另一个用例Support container sync则验证了assert.rejects(base.withExec([foobar]).sync(), ExecError)说明即使是很短的命令如不存在的foobar也会以ExecError形式暴露捕获路径是稳定一致的。常见误用与排查建议在非 await 场景下误判错误类型如果异步调用未被await错误可能以NotAwaitedRequestErrorD108出现而不是ExecError先检查调用链是否完整await日志脱敏stdout/stderr可能包含敏感输出写入日志前按需截断或过滤cmd是参数数组注意拼接待执行命令时正确处理含空格参数区分错误层级连接、鉴权、GraphQL 协议类问题会以GraphQLRequestErrorD100或UnknownDaggerErrorD101抛出只有容器内命令真正失败才是ExecErrorD109据此可设计多级错误处理与重试策略。ExecError的完整字段与类型签名始终以仓库中的 API 参考文档 ExecError.md、基类文档 DaggerSDKError.md 为准结合 ExecError.ts 与 compute_query.ts 源码可完整还原其行为。【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考