GopeedLab/gopeed · error
invalid navigation state
Error message
invalid navigation state
What it means
navigationState() (internal/webview/goprovider/provider.go:402) evaluates an inline JS expression that returns an object literal {url, readyState} and requires the decoded result to be map[string]any. If Execute yields anything else — typically nil after the JS context was destroyed mid-navigation — this error returns. It is the shape-check between the JS bridge and the Go struct.
Source
Thrown at internal/webview/goprovider/provider.go:409
}
return false
}
func parseURL(raw string) (*url.URL, error) {
return url.Parse(raw)
}
func (p *pageWrapper) navigationState() (navigationState, error) {
value, err := p.Execute(`() => ({
url: String(location.href || ""),
readyState: document.readyState || "",
})`)
if err != nil {
return navigationState{}, err
}
stateMap, ok := value.(map[string]any)
if !ok {
return navigationState{}, fmt.Errorf("invalid navigation state")
}
state := navigationState{}
if urlValue, ok := stateMap["url"].(string); ok {
state.URL = urlValue
}
if readyValue, ok := stateMap["readyState"].(string); ok {
state.ReadyState = readyValue
}
return state, nil
}
func (p *pageWrapper) dispatch(fn func(w webview.WebView) error) error {
p.mu.Lock()
if p.closed {
p.mu.Unlock()
return fmt.Errorf("webview page is closed")
}
w := p.viewView on GitHub (pinned to 7b7327ffb3)
Solutions
- Retry the state read after a short delay — transient nulls during navigation are the common cause
- Ensure the page is still open and the navigation has settled before querying state
- If persistent, verify the Execute path end-to-end with a trivial expression like '() => 1' to isolate bridge problems
Example fix
// before
state, err := page.NavigationState() // "invalid navigation state" mid-navigation
// after
var state map[string]any
for attempt := 0; attempt < 3; attempt++ {
v, err := page.Execute(`() => ({ url: location.href, readyState: document.readyState })`)
if err == nil {
if m, ok := v.(map[string]any); ok {
state = m
break
}
}
time.Sleep(200 * time.Millisecond) // let the navigation settle
} Defensive patterns
Strategy: retry
Validate before calling
// Tolerant state read: retry while the JS context settles
func readNavState(page enginewebview.Page) (map[string]any, error) {
for attempt := 0; attempt < 3; attempt++ {
v, err := page.Execute(`() => ({ url: String(location.href || ""), readyState: document.readyState || "" })`, nil)
if err == nil {
if m, ok := v.(map[string]any); ok {
return m, nil
}
}
time.Sleep(200 * time.Millisecond)
}
return nil, errors.New("navigation state unavailable")
} Type guard
func isNavState(v any) bool {
m, ok := v.(map[string]any)
return ok && m["url"] != nil
} Try / catch
v, err := page.Execute(expr, nil)
if err == nil {
if m, ok := v.(map[string]any); !ok {
// transient during navigation: back off once, then fail
time.Sleep(250 * time.Millisecond)
v, err = page.Execute(expr, nil)
}
} Prevention
- Expect null results during navigation windows; design polls to tolerate them
- Verify the Execute bridge with a trivial expression when this error persists
- Do not query state on a page that may already be closed
When it happens
Trigger: Polling navigation state exactly while the page navigates or is destroyed (eval returns null/undefined); an Execute plumbing fault where the callback resolves with a non-object JSON value; a closed or crashed render process making the eval return nothing.
Common situations: Happens transiently during waitForNavigation polling windows on fast navigations; persistent when the page crashes or the bridge callback name is misconfigured so results never arrive in object form.
Related errors
AI-assisted analysis of GopeedLab/gopeed@7b7327ffb3 (2026-08-16).
Data as JSON: /api/errors/597edfe529f4a1fd.
Report an issue: GitHub.