diff --git a/apps/ai-game-creator-shell/src-tauri/src/export/registry.rs b/apps/ai-game-creator-shell/src-tauri/src/export/registry.rs index 569758eb9..d7de77b46 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/export/registry.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/export/registry.rs @@ -72,6 +72,14 @@ where write_atomically(path, &created)?; (created, true) } + Err(error) if error.kind() == std::io::ErrorKind::InvalidData => { + // 非 UTF-8 字节就是「内容不是本目标期望的形状」,与 JSON 解析失败同类;落进通用 Io 会 + // 被报成「路径 / 权限故障」,把用户和 agent 往修权限的方向引。 + return Err(RegistryError::Malformed { + path: path.to_path_buf(), + cause: format!("注册表不是有效 UTF-8:{error}"), + }); + } Err(error) => { return Err(RegistryError::Io { path: path.to_path_buf(), @@ -219,6 +227,21 @@ mod tests { assert_eq!(fs::read_to_string(&path).unwrap(), "{ not json"); } + #[test] + fn rejects_non_utf8_content_as_malformed() { + let path = fixture_directory("non-utf8").join("target.json"); + fs::write(&path, [0xff, 0xfe, 0x00]).unwrap(); + let empty = Fixture { + name: String::new(), + }; + + let error = load_or_create(&path, &empty).expect_err("invalid utf-8 must fail closed"); + assert!( + matches!(error, RegistryError::Malformed { .. }), + "非 UTF-8 必须报成 malformed,而不是 host/path 故障:{error:?}" + ); + } + #[test] fn rejects_unknown_fields_so_agent_drift_is_visible() { let path = fixture_directory("unknown").join("target.json");