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
- Run EnsureBrowser (or the image build step that installs the bundled browser) once with network access so the binary is present
- Check the binary path is executable (chmod +x) and matches the running OS/arch
- Verify shared-library dependencies for Chromium exist (ldd) in slim images
- 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
- Call EnsureBrowser during image build/startup and fail early with a clear log
- Verify the binary matches the container OS/arch and is executable
- Check Chromium shared-library deps in slim images
- Ensure network/proxy allows the one-time browser download
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
- 下载内置浏览器失败: %w 本项目只用内置浏览器,缺它不继续。请检查网络后重试; 离线环境可手动下载 %s,解压
- 解压后未找到二进制 %s
- 落点 (%.0f,%.0f) 在视口 %.0fx%.0f 之外
- 导航到发布页面失败
- path is required
AI-assisted analysis of xpzouying/xiaohongshu-mcp@332d196854 (2026-09-05).
Data as JSON: /api/errors/b833d2dbf7a8ee8c.
Report an issue: GitHub.