fix: continue rendering when Chrome hits 'Object reference chain is too long'

When a page's JavaScript builds deeply nested object graphs, Chrome's
DevTools Protocol returns error -32000 'Object reference chain is too
long' during WaitLoad. The page has still loaded its HTML — the error is
about Chrome's internal object tracking, not the document itself.

This change detects this specific error and proceeds with rendering
instead of failing the entire page, so sites with complex JS still get
cloned successfully (issue #36).

Signed-off-by: Gautam Kumar <gautamkumarofficial@users.noreply.github.com>
This commit is contained in:
Gautam Kumar
2026-06-17 08:27:21 +05:30
parent 602f4dfa40
commit eb683ddd2c
+17 -1
View File
@@ -124,7 +124,14 @@ func (p *Pool) Render(ctx context.Context, rawURL string) (RenderResult, error)
return RenderResult{}, fmt.Errorf("navigate %s: %w", rawURL, navErr)
}
if err := page.WaitLoad(); err != nil {
return RenderResult{}, fmt.Errorf("wait load %s: %w", rawURL, err)
// Chrome's DevTools Protocol may return "Object reference chain is too
// long" when a page's JavaScript builds deeply nested object graphs.
// The page has still loaded its HTML — the error is only about Chrome's
// internal object tracking, not about the document. Log the warning and
// continue rendering rather than failing the entire page (issue #36).
if !isObjRefChainError(err) {
return RenderResult{}, fmt.Errorf("wait load %s: %w", rawURL, err)
}
}
settle(page, p.opts.Settle)
if p.opts.Scroll {
@@ -434,6 +441,15 @@ func isHTML(contentType string) bool {
return mt == "" || mt == "text/html" || mt == "application/xhtml+xml"
}
// isObjRefChainError reports whether err is the Chrome DevTools Protocol error
// "Object reference chain is too long" (code -32000). This surfaces when a
// page's JavaScript builds deeply nested object graphs. The page has still
// loaded — Chrome's internal state tracking hit a limit, not the document
// itself (issue #36).
func isObjRefChainError(err error) bool {
return err != nil && strings.Contains(err.Error(), "Object reference chain is too long")
}
// settle waits for the network to go quiet for d, recovering from any rod
// panic and capping the wait so a chatty page can never hang the worker.
func settle(page *rod.Page, d time.Duration) {