Skip to content

[Bug] macOS 主进程抛 Failed to register protocol: cache #445

Open

Description

@LOST-e-t

检查清单

  • 我已检索仓库中所有的 Issues,确保我没有重复提交问题;或有相似 Issue,但我觉得我的情况不包含在那个相似 Issue 之内
  • 我已经找到了可以复现这个问题的方法,并且写在了下面的「具体信息」中
  • 此问题可以在我的设备和当前环境中稳定复现
  • 此问题可以在最新版本 (Latest Release) 中复现
  • 此问题是在我更新到当前版本后才出现的

环境信息

环境

  • SPlayer-Next 1.2.0,由 SPlayer-Next-1.2.0-arm64.dmg 安装
  • macOS 27.2 (26B123),Apple Silicon M4 / 24GB
  • Electron 44.9.0,Chromium 152.0.7977.167
  • 两个 CPU 架构包内的 out/main/index.js 哈希一致:
    • x64 包:fe4f27519619290447c62781e6173223e04133de010fb92bdaa025460706e1b4
    • arm64 包:fe4f27519619290447c62781e6173223e04133de010fb92bdaa025460706e1b4
    • 两者均为 790307 bytes

具体信息

[Bug] macOS 主进程抛 Failed to register protocol: cache

此bug再出现后由AI处理并整理成报告,AI生成内容可能有误,受限于本人的能力无法辨别,但复现方法已经本人真实测试过可以复现。

Image

实际报错

A JavaScript error occurred in the browser process

Error: Failed to register protocol: cache
    at Protocol.handle (node:electron/js2c/browser_init:1:68328)
    at handleCacheProtocolOnPartition (file:///Applications/SPlayer-Next.app/Contents/Resources/app.asar/out/main/index.js:2631:44)
    at createMainWindow (file:///Applications/SPlayer-Next.app/Contents/Resources/app.asar/out/main/index.js:2721:2)
    at EventEmitter.<anonymous> (file:///Applications/SPlayer-Next.app/Contents/Resources/app.asar/out/main/index.js:24924:10)
    at EventEmitter.emit (node:events:514:28)

报错后检查进程列表(pgrep -fl SPlayer-Next):存在 main / gpu / network 三个进程,无 Renderer 进程。

复现步骤

  1. 启动 SPlayer-Next,主窗口出现
  2. 在全屏视角下,点窗口右上角叉最小化到托盘
  3. 此时全屏界面黑屏,无法自动退出全屏界面
  4. dock栏右键点击退出,此时程序报错

源码位置

对应 main 分支(提交 e944efe,2026-11-03):

  • electron/main/utils/protocol.ts:68 — handleCacheProtocolOnPartition
  • electron/main/window/main.ts:36 — createMainWindow 内调用

该提交下这两处与 1.2.0 发布版逻辑一致,均无重复注册保护。

重复检查

已遍历本仓库 65 条 open issue 与 109 条 closed issue 标题,未发现同一错误(Failed to register protocol: cache)。

相关代码

行号为解包 app.asar 后逐行遍历的实际行号。错误栈中报出的行号一律比实际少 1(栈中 2631 / 2721 / 24924 对应实际的 2632 / 2722 / 24925)。

协议注册函数(2625–2633)

var handleCacheProtocol = () => {
	protocol.handle(SCHEME$1, cacheHandler);
};
/**
* 在指定 partition 的 session 上注册 cache:// 协议处理
*/
var handleCacheProtocolOnPartition = (partition) => {
	session.fromPartition(partition).protocol.handle(SCHEME$1, cacheHandler);
};

createMainWindow(2718 起,第 5 行调用注册)

var createMainWindow = () => {
	const remember = store$1.get("system.rememberWindowState") ?? true;
	/** 旧版窗口状态 */
	const legacyState = remember ? store$1.get("windowStates.main") : void 0;
	handleCacheProtocolOnPartition(MAIN_PARTITION);
	const borderlessWindow = store$1.get("system.borderlessWindow") ?? true;
	mainWindow = createWindow({
		width: legacyState?.width ?? 1280,
		// ...

window-all-closed(24814)

app.on("window-all-closed", () => {
	if (process.platform !== "darwin") app.quit();
});

窗口 closed 回调(2803)

mainWindow.on("closed", () => {
	setMainWindowVisible(false);
	setPlayerExpanded(false);
	mainWindow = null;          // 2806
});

activate 回调(24922)

app.on("activate", () => {
	if (isMac) {
		if (getMainWindow()) focusMainWindow();
		else createMainWindow();   // 24925
		return;
	}
	if (BrowserWindow.getAllWindows().length === 0) createMainWindow();
});

getMainWindow(2813)

var getMainWindow = () => {
	if (mainWindow && !mainWindow.isDestroyed()) return mainWindow;
	return null;
};

全文检索结果

对 out/main/index.js(790307 bytes)检索 unhandle 与 unintercept,无任何匹配。

建议修复

按 partition 记录注册状态:

const registeredCachePartitions = new Set();

var handleCacheProtocolOnPartition = (partition) => {
	if (registeredCachePartitions.has(partition)) return;
	registeredCachePartitions.add(partition);
	session.fromPartition(partition).protocol.handle(SCHEME$1, cacheHandler);
};

第 2625–2627 行的 handleCacheProtocol() 同样直接调用 protocol.handle,代码中未见重复调用保护。

electron/main/window/main.spec.ts 已对 handleCacheProtocolOnPartition 做了 mock,可在此补充"重复调用只注册一次"的断言。

恢复方式(实测)

结束全部相关进程后重新启动,进程列表出现 main / gpu / network / Renderer × 2:

kill <主进程 PID>,再 open -a /Applications/SPlayer-Next.app
→ 进程:main / gpu / network / Renderer × 2

附带反馈

macOS 包的代码签名状态(codesign -dv 实测):

CodeDirectory v=20400 size=392 flags=0x20002(adhoc,linker-signed)
TeamIdentifier=not set

本次安装时清除了 com.apple.quarantine 并执行了本地 ad-hoc 重签名。

Activity

  1. github-actions commented on Nov 4, 2026

    @github-actions

    👋 @LOST-e-t

    感谢提交 Issue!我们已经收到您的反馈,会尽快确认您的问题。

    Thanks for opening this issue! We have received your report and will review it as soon as possible.

  2. Aerytgophilis commented on Nov 5, 2026

    @Aerytgophilis

    补充一条不同的触发路径,供参考(同环境:SPlayer-Next 1.2.0 arm64 / macOS 27.2 26B123 / Apple Silicon)。

    触发方式:正常退出流程卡住,而不是全屏最小化

    1. 新安装后首次启动,停留在首页,未登录、未播放
    2. 通过系统发出退出请求(osascript -e 'quit app "SPlayer-Next"',效果等同 Dock 右键「退出」)
    3. 日志出现 应用即将退出,清理资源 后再无任何清理相关日志,进程没有退出(main / GPU / helper 仍在),主窗口已被销毁
    4. 此后点击 Dock 图标 → activate → createMainWindow() → Failed to register protocol: cache,约 80 秒内连续触发 6 次
    5. 之后再发 SIGTERM 进程仍不退出,只能强制结束

    日志节选(路径已脱敏):

    [11:45:14.600] [info]  (core) 应用即将退出,清理资源
    [11:45:14.628] [error] (core) [login] loadURL failed: Error: ERR_FAILED (-2) loading 'https://music.163.com/#/login'
    [11:45:16.715] [error] Unhandled Error: Failed to register protocol: cache
    ...(同样的错误共 6 次,最后一次 11:46:33)
    

    可能相关的第二个问题

    electron/main/core/lifecycle.ts 的 runCleanupTasks() 里,只有「流媒体播放会话」这一项用 Promise.race 加了 2 秒超时,其余各项(插件、播放事件桥、更新服务、数据库等)都是无超时的 await。只要其中一项的 Promise 一直不 resolve,cleanupFinished 就永远不会被置为 true,before-quit 会一直 preventDefault(),应用就停在「窗口已销毁、进程仍在」的状态,正好进入本 issue 的报错路径。

    本次没能确定具体是哪一项卡住(当时外部 API 与 MCP 均未启用,按代码会直接返回)。

    建议

    1. 采纳正文里的 per-partition 去重修复(Set 记录已注册的 partition)
    2. 给 runCleanupTasks 加一个整体或逐项超时,超时后记日志并 app.exit() 兜底,避免进程半退出
    3. 可选:在每个清理任务开始和结束时打日志,方便定位到底是哪一项卡住
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions