CANN Runtime 错误码 EH0003 深入解析:文件路径非法(Invalid Path)的触发原理与排查方法
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
导读
EH0003 是 CANN runtime(CANN 运行时组件)中一类面向用户的**文件路径非法(File Operation Error / Invalid Path)**错误码,当应用传入的配置文件路径不存在、无法解析或打开失败时,runtime 会以Path %s is invalid. Reason: %s.的固定模板向用户报告。本文以 EH0003-File_Operation_Error_Invalid_Path.md 为骨架,结合本仓库中该错误码的注册定义、底层格式化实现、两处真实触发源码与对应单元测试,完整还原 EH0003 的产生链路,并给出从报错信息到根因定位的实战排查步骤。
一、错误信息格式
EH0003 的报错格式固定如下,其中占位符%s的含义依次为文件路径、报错原因:
Path %s is invalid. Reason: %s.| 占位符 | 含义 | 典型取值 |
|---|---|---|
第 1 个%s(path) | 传入或解析得到的文件路径 | /tmp/invalid.json、./a.text |
第 2 个%s(reason) | 具体的失败原因 | file open failed、无法解析真实路径时的系统错误信息 |
报错示例:
Path /tmp/invalid.json is invalid. Reason: file open failed.这段报错表达了两层信息:第一,runtime 认为/tmp/invalid.json这个路径不合法;第二,非法的原因在于"文件打开失败"。排查时应优先关注 Reason 部分携带的具体失败原因,它直接指向根因方向。
二、EH0003 在错误码体系中的位置
EH0003 属于ACL Errors(EH 系列)外部错误码。在错误码索引文档 ACL-Errors.md 中,EH 系列覆盖了参数非法(EH0001/EH0002)、文件操作错误(EH0003/EH0004)、功能不支持(EH0006)等一系列通用用户侧错误;EH0003 的命名即表明其语义为File Operation Error - Invalid Path。
从代码注册层面看,EH0003 在 runtime 中被统一定义为常量,供各模块复用:
- src/acl/common/log_inner.h 中声明了
constexpr const char_t* const INVALID_PATH_MSG = "EH0003";,与INVALID_PARAM_MSG(EH0001)、INVALID_NULL_POINTER_MSG(EH0002)等并列,属于 ACL 公共错误消息常量; - src/runtime_compact/c_base/src/error_manager.c 的错误码注册表
ERROR_MAP中登记了该错误码的完整模板:{"EH0003", "Path %s is invalid. Reason: %s.", NULL, NULL, {"path", "reason"}},其中第 5 个字段
{"path", "reason"}是参数列表(argList),它规定了该错误模板各%s位对应的参数名,与报错格式中的占位符一一对应。这也是"报错格式中第 1 个%s为文件路径、第 2 个%s为报错原因"这一约定的代码级来源。
ERROR_MAP中的possibleCause与solution字段对 EH0003 均为空,说明该错误码不附带固定的原因与解决建议,需要根据每次上报时携带的 path 与 reason 动态判断。
三、哪些场景会触发 EH0003:从源码看触发链路
EH0003 并非只在"文件不存在"这一种场景下出现。在本仓库中,至少存在两处明确上报该错误码的源码路径,分别位于 runtime 配置读取与 JSON 配置解析两个环节。
3.1 场景一:runtime 配置路径无法解析或打开失败
src/acl/aclrt_impl/acl_rt_impl_base.cpp 中的GetStrFromConfigPath负责把外部传入的配置文件路径读取为字符串,它包含两道检查,任一失败都会上报 EH0003:
真实路径解析失败:调用
mmRealPath(configPath, realPath, MMPA_MAX_PATH)对传入路径做规范化解析,若返回非EN_OK(例如路径指向不存在的目录、包含无法解析的符号链接、路径过长等),则上报:acl::AclErrorLogManager::ReportInputError( acl::INVALID_PATH_MSG, std::vector<const char*>({"path", "reason"}), std::vector<const char*>({configPath, formatErrMsg.c_str()})); ACL_LOG_ERROR("Invalid file: %s", configPath); return ACL_ERROR_INVALID_FILE;此时 Reason 携带的是
mmGetErrorCode()格式化后的系统错误信息,报错示例中的/tmp/invalid.json即属于此类路径形态。文件打开失败:路径解析成功后,用
std::ifstream file(realPath, std::ios::binary)以二进制方式打开文件,若打开失败(文件不存在、权限不足、被占用等),则上报:acl::AclErrorLogManager::ReportInputError( acl::INVALID_PATH_MSG, std::vector<const char*>({"path", "reason"}), std::vector<const char*>({configPath, "file open failed"}));这正是错误码文档中报错示例
Reason: file open failed.的源码出处。
无论哪一道检查失败,函数都会返回ACL_ERROR_INVALID_FILE给上层调用者,同时通过日志打印Invalid file: <path>或Failed to open file: <path>便于定位。
3.2 场景二:JSON 配置文件非法路径检查
src/acl/common/json_parser.cpp 中JsonParser::IsValidFileName负责在解析 JSON 配置前校验文件名合法性,同样有两处 EH0003 上报:
mmRealPath(fileName, trustedPath, MMPA_MAX_PATH)返回非EN_OK时上报 EH0003,Reason 为AclGetErrorFormatMessage(mmGetErrorCode())得到的格式化错误信息,同时打印日志[Trans][RealPath]the file path %s is not like a real path, mmRealPath returns %d, errMessage is %s;mmStatGet(trustedPath, &pathStat)获取文件状态失败时再次上报 EH0003,Reason 为格式化错误信息,对应日志[Get][FileStatus]cannot get config file status, which path is %s, maybe does not exist, return %d, errcode %d。
从这段实现可以推断:EH0003 的 Reason 部分并不总是固定的 "file open failed",它可能是一段来自底层系统调用的可读错误描述。因此排查 EH0003 时,必须完整读取 Reason 中携带的具体文本,而不能只依赖固定的示例。
3.3 参数上报机制小结
两处触发点都调用了acl::AclErrorLogManager::ReportInputError(INVALID_PATH_MSG, {"path", "reason"}, {path, reason}),其参数顺序与ERROR_MAP注册表(src/runtime_compact/c_base/src/error_manager.c)中的{"path", "reason"}严格对应,最终由 error manager 依据模板完成格式化并生成用户可见的报错文本。
四、单元测试中的 EH0003 验证
runtime 的错误码管理单元测试 tests/ut/runtime/runtime_c/testcase/c_base/error_manager_test.cc 对 EH0003 的格式化行为做了直接验证:
REPORT_INPUT_ERROR("EH0003", ARRAY("path", "reason", "value"), ARRAY("./a.text", "cannot find", "100")); char* errmsg = GetErrorMessage(); ASSERT_STREQ( errmsg, "EH0001: Value 25 for x is invalid. Reason: The value is too small.\r\n" " TraceBack (most recent call last):\r\n" " Argument ll must not be NULL.\r\n" " Path ./a.text is invalid. Reason: cannot find.\r\n");该用例同时说明了两个重要行为:
- 模板格式化正确性:传入 path=
./a.text、reason=cannot find时,最终输出Path ./a.text is invalid. Reason: cannot find.,与本文开头给出的报错格式完全一致; - 参数冗余容忍:即使调用方多传了一个模板参数列表中不存在的
value参数(ARRAY("path", "reason", "value")),EH0003 仍能正常格式化,多余参数不会导致模板错位或格式化失败,印证了 error manager 对参数数量的容错处理。
五、解决方法与排查步骤
5.1 官方解决方法
根据错误码文档 EH0003-File_Operation_Error_Invalid_Path.md,EH0003 的解决方法是:
根据报错检查文件是否存在。
5.2 结合源码的完整排查清单
仅"检查文件是否存在"还不够,结合 3.1 与 3.2 两处触发源码,建议按下述顺序逐项核查:
读取完整报错:先获取完整的 EH0003 文本,重点是
Reason:之后的具体原因——它可能是file open failed,也可能是底层系统调用返回的可读错误描述,后者直接决定排查方向。核对文件是否存在:使用
ls -l、stat等命令确认报错路径对应的文件真实存在,且不是指向失效位置的符号链接(mmRealPath解析失败同样会触发 EH0003)。核对文件类型与权限:
- 路径指向的必须是普通文件,目录、设备文件等非普通文件在
IsValidFileName中会命中"非普通文件"检查并报错(源码见 src/acl/common/json_parser.cpp,该分支使用 EH0004 模板); - 当前进程对文件须具备读取权限,且父目录具备可访问(可执行)权限,否则
std::ifstream打开会失败并报file open failed。
- 路径指向的必须是普通文件,目录、设备文件等非普通文件在
核对路径写法:
- 尽量使用绝对路径,避免依赖进程当前工作目录的相对路径;
- 检查路径中是否包含未展开的环境变量、特殊字符或超出
MMPA_MAX_PATH的长路径,这些都会导致mmRealPath解析失败。
结合日志定位:EH0003 上报时通常伴随
ACL_LOG_ERROR日志输出,如Invalid file: <path>、Failed to open file: <path>(src/acl/aclrt_impl/acl_rt_impl_base.cpp)或[Trans][RealPath]...、[Get][FileStatus]...(src/acl/common/json_parser.cpp)。检索运行日志中与报错路径一致的关键字,可确认触发环节是"配置读取"还是"JSON 解析"。确认返回码语义:在配置读取场景中,EH0003 对应的上层返回码是
ACL_ERROR_INVALID_FILE(见 src/acl/aclrt_impl/acl_rt_impl_base.cpp),可在应用侧据此区分错误类别,与"参数非法(EH0001)""内存不足(EH0010)"等错误码区分处理。
六、小结
EH0003 是 CANN runtime 面向用户的通用文件路径错误码,其报错模板Path %s is invalid. Reason: %s.由错误码注册表 src/runtime_compact/c_base/src/error_manager.c 统一定义,实际触发点覆盖 runtime 配置路径读取(src/acl/aclrt_impl/acl_rt_impl_base.cpp)与 JSON 配置文件名校验(src/acl/common/json_parser.cpp)两条链路。排查时以报错中的 Reason 为第一线索,依次核对文件存在性、文件类型与权限、路径写法,并结合运行日志确认触发环节,即可快速收敛到根因。
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考