环境
- 组件:cosh-ng
- 版本:0.11.0
- 测试环境:Linux x86_64 (Alinux 4)
复现步骤
- 执行
cosh-cli checkpoint diff --workspace <path> --from <bad-id> --to <bad-id>(使用不存在的 snapshot id)
- 观察
error.message 字段
预期
error.message 为友好措辞,不含内部 socket 路径或底层 Rust std::io 错误原文
error.code 准确反映"协议帧异常"或"daemon 返回异常响应"(而非 CheckpointDaemonUnavailable,因为 daemon 实际可达)
实际
error.code = CheckpointDaemonUnavailable
error.message = "I/O error while read response length: failed to fill whole buffer (<内部 socket 路径>)"
"failed to fill whole buffer" 是 Rust std::io 原始错误消息(UnexpectedEof)
- 内部 socket 路径被直接拼进用户可见的 message
根因(源码定位)
crates/cosh-platform/src/checkpoint.rs classify_io_error() 的 _ fallthrough 分支把 socket_path 与原始 io 错误拼进 message:
fn classify_io_error(e: std::io::Error, socket_path: &str, context: &str) -> CoshError {
match e.kind() {
std::io::ErrorKind::BrokenPipe => ...,
std::io::ErrorKind::ConnectionReset => ...,
std::io::ErrorKind::TimedOut => ...,
std::io::ErrorKind::ConnectionRefused => ...,
_ => CoshError::new(
ErrorCode::CheckpointDaemonUnavailable,
format!("I/O error while {}: {} ({})", context, e, socket_path), // ← 泄漏
"checkpoint",
)
.recoverable(true),
}
}
read_exact 返回 UnexpectedEof("failed to fill whole buffer")时落入 _ 分支(未单独处理),把 socket_path 拼进 message。daemon 返回非帧格式响应(如错误字符串或提前关闭连接)即触发此路径。
影响
- 内部 socket 路径泄漏到用户/Agent 可见输出,暴露运行时文件系统布局
- 违反项目自身输出契约(不应在用户可见输出中暴露内部路径)
CheckpointDaemonUnavailable 分类不准 — daemon 实际可达,只是协议帧异常,Agent 据此可能误判为"重启 daemon 即可"
- 错误消息低层、不友好,Agent 难以据此决策
复现稳定性
3/3 稳定复现
修复建议
_ fallthrough 不在 message 里包含 socket_path(可放 error.details 字段,不进 message)
- 为
UnexpectedEof 增加专门分支:映射为友好 message(如 "daemon response incomplete")与准确的 ErrorCode(如 CheckpointProtocolError 或 Unknown)
- 区分"daemon 不可达"(ConnectionRefused/BrokenPipe)与"daemon 返回异常帧"(UnexpectedEof)
分类建议
PRODUCT_BUG
环境
复现步骤
cosh-cli checkpoint diff --workspace <path> --from <bad-id> --to <bad-id>(使用不存在的 snapshot id)error.message字段预期
error.message为友好措辞,不含内部 socket 路径或底层 Rust std::io 错误原文error.code准确反映"协议帧异常"或"daemon 返回异常响应"(而非CheckpointDaemonUnavailable,因为 daemon 实际可达)实际
error.code = CheckpointDaemonUnavailableerror.message = "I/O error while read response length: failed to fill whole buffer (<内部 socket 路径>)""failed to fill whole buffer"是 Rust std::io 原始错误消息(UnexpectedEof)根因(源码定位)
crates/cosh-platform/src/checkpoint.rsclassify_io_error()的_fallthrough 分支把socket_path与原始 io 错误拼进 message:read_exact返回UnexpectedEof("failed to fill whole buffer")时落入_分支(未单独处理),把socket_path拼进 message。daemon 返回非帧格式响应(如错误字符串或提前关闭连接)即触发此路径。影响
CheckpointDaemonUnavailable分类不准 — daemon 实际可达,只是协议帧异常,Agent 据此可能误判为"重启 daemon 即可"复现稳定性
3/3 稳定复现
修复建议
_fallthrough 不在 message 里包含socket_path(可放error.details字段,不进 message)UnexpectedEof增加专门分支:映射为友好 message(如"daemon response incomplete")与准确的ErrorCode(如CheckpointProtocolError或Unknown)分类建议
PRODUCT_BUG