GopeedLab/gopeed · error

webview page is closed

Error message

webview page is closed

What it means

pageWrapper.Execute (internal/webview/goprovider/provider.go:186) marshals the call, allocates a reqID channel, then checks p.closed under the page mutex. Every Execute/Evaluate call made after Close() set that flag fails immediately with this error instead of dispatching to the dead webview.

Solutions

  1. Stop all background tasks that touch the page before calling Close()
  2. Treat Close as terminal: never reuse the wrapper, create a new page for the next navigation
  3. Route every page access through your own guard that checks a 'closed' flag you set at shutdown

Example fix

// before
page.Close()
_, err := page.Execute(`() => location.href`) // "webview page is closed"

// after
cancelPollers()
if err := page.Close(); err != nil { return err }
page = nil // make stale references obvious; open a new page when needed
Defensive patterns

Strategy: validation

Validate before calling

// Track page lifetime in the caller
type pageRef struct {
    mu     sync.Mutex
    page   enginewebview.Page
    closed bool
}

func (r *pageRef) execute(expr string, args []any) (any, error) {
    r.mu.Lock()
    if r.closed || r.page == nil {
        r.mu.Unlock()
        return nil, errors.New("page already closed")
    }
    r.mu.Unlock()
    return r.page.Execute(expr, args)
}

Try / catch

val, err := r.execute(expr, args)
if err != nil && strings.Contains(err.Error(), "webview page is closed") {
    return nil, ErrSessionClosed // map to your own terminal condition; do not retry
}

Prevention

When it happens

Trigger: Calling page.Execute or the navigation-state polling after page.Close() returned; a concurrent Close() that wins the race while an Evaluate is being set up; keeping a stale page reference in application state after closing the window.

Common situations: Cleanup paths that close the page while background pollers (progress tickers, state watchers) are still running; promise chains that resolve after the user closed the window; caches of page objects that outlive their window.

Related errors


AI-assisted analysis of GopeedLab/gopeed@7b7327ffb3 (2026-08-16). Data as JSON: /api/errors/808b5a1a411e8864. Report an issue: GitHub.

Appendix: source

Thrown at internal/webview/goprovider/provider.go:202

	return nil
}

func (p *pageWrapper) Execute(expression string, args ...any) (any, error) {
	startedAt := time.Now()
	if args == nil {
		args = []any{}
	}
	argsJSON, err := json.Marshal(args)
	if err != nil {
		return nil, err
	}
	reqID := fmt.Sprintf("req-%d", providerSeq.Add(1))
	ch := make(chan evalResult, 1)

	p.mu.Lock()
	if p.closed {
		p.mu.Unlock()
		return nil, fmt.Errorf("webview page is closed")
	}
	p.pending[reqID] = ch
	p.mu.Unlock()

	script := buildExecuteScript(p.callbackName, reqID, expression, string(argsJSON))
	if err := p.dispatch(func(w webview.WebView) error {
		w.Eval(script)
		return nil
	}); err != nil {
		p.mu.Lock()
		delete(p.pending, reqID)
		p.mu.Unlock()
		return nil, err
	}

	result := <-ch
	if result.err != nil {
		p.tracef("execute failed %dms err=%v", time.Since(startedAt).Milliseconds(), result.err)

View on GitHub (pinned to 7b7327ffb3)