xpzouying/xiaohongshu-mcp · critical

内置浏览器不可用,拒绝启动: %v

Error message

内置浏览器不可用,拒绝启动: %v

What it means

NewBrowser deliberately panics with "内置浏览器不可用,拒绝启动" when EnsureBrowser cannot produce the bundled Chromium binary path. This is an intentional fail-fast: the code refuses to silently fall back to a rod-downloaded default Chromium that would ignore the fingerprint flags. It is a panic, not a returned error, so it crashes the process at startup.

Source

Thrown at browser/browser.go:62

		cred = "***:***"
	}
	// 直接在原串替换 userinfo,避免 url.String() 把 * 编码成 %2A(日志变乱码)。
	return strings.Replace(proxyURL, u.User.String()+"@", cred+"@", 1)
}

func NewBrowser(headless bool, options ...Option) *headless_browser.Browser {
	cfg := &browserConfig{}
	for _, opt := range options {
		opt(cfg)
	}

	// 只用内置浏览器,没有别的来源。二进制必须显式传给 go-rod,
	// 否则 rod 会自行下载一个默认 Chromium:它不是内置浏览器,也不认识下面
	// 这些 flag(未知 flag 被静默忽略,日志照样打印 "fingerprint enabled"),
	// 属于无声降级。宁可不启动,也不启动一个不对的浏览器。
	binPath, err := EnsureBrowser()
	if err != nil {
		panic(fmt.Sprintf("内置浏览器不可用,拒绝启动: %v", err))
	}

	opts := []headless_browser.Option{
		headless_browser.WithHeadless(headless),
		// 用内置浏览器的默认配置,不强制 UA。
		headless_browser.WithFingerprint(""), // 空 = 按运行 OS 自动:Linux→windows,mac→macos
		headless_browser.WithStealthJS(false),
		headless_browser.WithLanguage("zh-CN"), // 面向小红书
		// 品牌报 Chrome。
		// 注:hardware-concurrency 不设,交给 seed 派生。
		headless_browser.WithExtraFlags(map[string]string{"fingerprint-brand": "Chrome"}),
	}
	opts = append(opts, headless_browser.WithChromeBinPath(binPath))

	// 代理(由调用方经 Option 传入,env 读取放在入口层)。
	if cfg.proxy != "" {
		opts = append(opts, headless_browser.WithProxy(cfg.proxy))
		logrus.Infof("Using proxy: %s", maskProxyCredentials(cfg.proxy))

View on GitHub (pinned to 332d196854)

Solutions

  1. Run EnsureBrowser (or the image build step that installs the bundled browser) once with network access so the binary is present
  2. Check the binary path is executable (chmod +x) and matches the running OS/arch
  3. Verify shared-library dependencies for Chromium exist (ldd) in slim images
  4. Since this panics, wrap startup with recover or call EnsureBrowser yourself first and exit with a clear message

Example fix

// before
b := browser.NewBrowser(true) // panics if bundle missing
// after
if _, err := browser.EnsureBrowser(); err != nil {
    log.Fatalf("browser bundle unavailable: %v", err)
}
b := browser.NewBrowser(true)
Defensive patterns

Strategy: validation

Validate before calling

binPath, err := browser.EnsureBrowser()
if err != nil {
    log.Fatalf("bundled browser unavailable: %v", err) // explicit, before NewBrowser panics
}

Try / catch

func safeNewBrowser(headless bool) (b *headless_browser.Browser, err error) {
    defer func() { if r := recover(); r != nil { err = fmt.Errorf("browser init: %v", r) } }()
    return browser.NewBrowser(headless), nil
}

Prevention

When it happens

Trigger: EnsureBrowser fails: the bundled browser binary is missing from the image/deployment, the download/extract step failed (no network, disk full), the binary exists but is not executable (permissions) or built for the wrong OS/arch.

Common situations: Docker image built without the browser assets or on a mismatched architecture (arm64 image expectations vs amd64 binary); read-only filesystem preventing extraction; corporate proxy blocking the browser download; stripped-down distro missing shared libraries for Chromium.

Related errors


AI-assisted analysis of xpzouying/xiaohongshu-mcp@332d196854 (2026-09-05). Data as JSON: /api/errors/b833d2dbf7a8ee8c. Report an issue: GitHub.