现象
在 https://github.com/torvalds/uemacs 整页翻译时:
[PT] 翻译失败: [object DOMException]
DOMException 的真实 message(name + 描述)被 String(e) 吞掉,无法定位根因。
根因
entrypoints/content.ts:282-288 (togglePage() 的 catch 块):
} catch (e) {
console.error('[PT] 翻译失败:', e); // 原始对象,部分日志系统只展示 [object DOMException]
if (isMainFrame) {
toast(String(e), 'error'); // ← String(e) 在特定环境下产生 "[object DOMException]"
setBallState('error');
}
return 'error';
}
DOMException 继承自 Error,.name 与 .message 均已有值(如 HierarchyRequestError: Failed to execute 'appendChild'...),但 String(e) 在特定 console 实现中走的是 Object.prototype.toString 路径,输出 [object DOMException] 而非 .message。
应改为 e instanceof Error ? e.message : String(e)。
同类问题还存在于:
| 文件 |
行号 |
上下文 |
entrypoints/content.ts |
374, 376 |
popup reply String(e) |
entrypoints/background.ts |
79, 81 |
sendResponse 错误路径 |
src/engines/router.ts |
139 |
new EngineError(id, true, String(e)) |
可能的 DOMException 来源(待确认)
由于真实 name/message 被吞,只能根据 GitHub 页面特征推测。异常必须由 doTranslate() 内部抛出(该函数是 togglePage 中唯一被 await 的调用):
1. document.createTreeWalker() — walker.ts:33
根据 DOM 规范,acceptNode 过滤器内抛出的任何异常都会经 walker.nextNode() 向外传播。该过滤器对页面每个元素运行,是覆盖面最大的抛异常面:
applyCompat(el) → github.com 分支 (compat.ts:42-78) 调用 el.closest(...)
shouldSkipNonVisual(el) → el.closest(...) (classify.ts:67,70,73) + el.textContent / el.outerHTML (classify.ts:75,77)
hasNonTextContent(el) → el.querySelector(NON_TEXT_SELECTOR) (classify.ts:112)
walk(el.shadowRoot, ...) → 递归 shadow root(walker.ts 注释已记录此处历史 TypeError,是已知脆弱路径)
2. render() — renderer.ts:43
while (el.firstChild) origin.appendChild(el.firstChild);
appendChild 在层级冲突时抛出 HierarchyRequestError。GitHub 是 React SPA,页面可能在 collect() 采集 → await sendMessage → render() 之间已将被采集元素从 DOM 中移除或替换。
3. chrome.runtime.sendMessage() — content.ts:173
结构化克隆失败时抛出 DataCloneError(当前 payload 均为字符串/简单对象,不应触发;但扩展升级/重载导致的 context invalidated 也会走此 reject 路径)。
修复方案
1. 正确提取 DOMException 的 message(必须)
- toast(String(e), 'error');
+ const msg = e instanceof Error ? e.message : String(e);
+ toast(msg, 'error');
同步修复 console.error 及其他 4 处 String(e) 站点。
2. 为 shouldSkipNonVisual 增加防御(推荐)
GitHub 大量 Web Components(<relative-time>、<clipboard-copy>、<include-fragment> 等)上访问 textContent / outerHTML 的 getter 可能抛出。用 try-catch 包裹外层,失败时安全跳过(宁可漏翻单个可疑节点,也不要整页崩溃)。
3. 为 doTranslate 增加阶段标记(推荐)
在错误中携带当前操作上下文(collect / batch N / render),即使 .message 不完整也能缩小排查范围。
影响范围
- 任何
DOMException 场景(不限于 GitHub)都会因 String(e) 输出无意义字符串
- 用户看到 toast 显示
[object DOMException],无法采取任何行动
- 开发者无法从日志定位具体 DOM 操作失败点 —— 修复 1 是定位真正根因的前提条件
现象
在
https://github.com/torvalds/uemacs整页翻译时:DOMException的真实 message(name + 描述)被String(e)吞掉,无法定位根因。根因
entrypoints/content.ts:282-288(togglePage()的 catch 块):DOMException继承自Error,.name与.message均已有值(如HierarchyRequestError: Failed to execute 'appendChild'...),但String(e)在特定 console 实现中走的是Object.prototype.toString路径,输出[object DOMException]而非.message。应改为
e instanceof Error ? e.message : String(e)。同类问题还存在于:
entrypoints/content.tsString(e)entrypoints/background.tssendResponse错误路径src/engines/router.tsnew EngineError(id, true, String(e))可能的 DOMException 来源(待确认)
由于真实 name/message 被吞,只能根据 GitHub 页面特征推测。异常必须由
doTranslate()内部抛出(该函数是togglePage中唯一被 await 的调用):1.
document.createTreeWalker()—walker.ts:33根据 DOM 规范,
acceptNode过滤器内抛出的任何异常都会经walker.nextNode()向外传播。该过滤器对页面每个元素运行,是覆盖面最大的抛异常面:applyCompat(el)→ github.com 分支 (compat.ts:42-78) 调用el.closest(...)shouldSkipNonVisual(el)→el.closest(...)(classify.ts:67,70,73) +el.textContent/el.outerHTML(classify.ts:75,77)hasNonTextContent(el)→el.querySelector(NON_TEXT_SELECTOR)(classify.ts:112)walk(el.shadowRoot, ...)→ 递归 shadow root(walker.ts 注释已记录此处历史 TypeError,是已知脆弱路径)2.
render()—renderer.ts:43appendChild在层级冲突时抛出HierarchyRequestError。GitHub 是 React SPA,页面可能在collect()采集 →await sendMessage→render()之间已将被采集元素从 DOM 中移除或替换。3.
chrome.runtime.sendMessage()—content.ts:173结构化克隆失败时抛出
DataCloneError(当前 payload 均为字符串/简单对象,不应触发;但扩展升级/重载导致的 context invalidated 也会走此 reject 路径)。修复方案
1. 正确提取 DOMException 的 message(必须)
同步修复
console.error及其他 4 处String(e)站点。2. 为
shouldSkipNonVisual增加防御(推荐)GitHub 大量 Web Components(
<relative-time>、<clipboard-copy>、<include-fragment>等)上访问textContent/outerHTML的 getter 可能抛出。用 try-catch 包裹外层,失败时安全跳过(宁可漏翻单个可疑节点,也不要整页崩溃)。3. 为
doTranslate增加阶段标记(推荐)在错误中携带当前操作上下文(
collect/batch N/render),即使.message不完整也能缩小排查范围。影响范围
DOMException场景(不限于 GitHub)都会因String(e)输出无意义字符串[object DOMException],无法采取任何行动