{"record":{"id":"fba860a5a619da17","repo":"JuliusBrussee/caveman","slug":"resolve-node-returned-no-object","errorCode":null,"errorMessage":"resolve node returned no object","messagePattern":"resolve node returned no object","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"browse/cdp.go","lineNumber":407,"sourceCode":"\tif err := json.Unmarshal(res.Value, &out); err != nil {\n\t\treturn false, err\n\t}\n\treturn out, nil\n}\n\nfunc (d *CDPDriver) callOnNodeRaw(ctx context.Context, target Target, fn string) (*runtime.RemoteObject, error) {\n\tif target.BackendDOMNodeID <= 0 {\n\t\treturn nil, errors.New(\"missing backend DOM node id\")\n\t}\n\tvar res *runtime.RemoteObject\n\tvar exception *runtime.ExceptionDetails\n\tif err := chromedp.Run(ctx, chromedp.ActionFunc(func(actionCtx context.Context) error {\n\t\tobj, err := dom.ResolveNode().WithBackendNodeID(cdp.BackendNodeID(target.BackendDOMNodeID)).Do(actionCtx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif obj == nil {\n\t\t\treturn errors.New(\"resolve node returned no object\")\n\t\t}\n\t\tres, exception, err = runtime.CallFunctionOn(fn).WithObjectID(obj.ObjectID).Do(actionCtx)\n\t\treturn err\n\t})); err != nil {\n\t\treturn nil, err\n\t}\n\tif exception != nil {\n\t\treturn nil, errors.New(\"browser function threw\")\n\t}\n\tif res == nil {\n\t\treturn nil, errors.New(\"browser function returned no result object\")\n\t}\n\treturn res, nil\n}\n\nfunc jsString(s string) string {\n\tb, _ := json.Marshal(s)\n\treturn string(b)","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/browse/cdp.go#L389-L425","documentation":"Returned inside callOnNodeRaw's chromedp action when dom.ResolveNode().WithBackendNodeID(...) succeeds without error but returns a nil remote object. ResolveNode should produce a RemoteObject for the node's JS wrapper; nil means Chrome could not produce one (node in a destroyed context, or backend id no longer valid even though the call did not error), so there is no ObjectID to CallFunctionOn with and the driver aborts.","triggerScenarios":"Evaluating a function on a node whose backing JS object is gone: after navigation destroyed the frame, the node was removed from the document, or the backend id references a node in a swapped-out frame.","commonSituations":"Acting on a uid captured before an SPA transition; deferred actions on nodes a script has since replaced; cross-origin iframe nodes whose process was swapped.","solutions":["Take a new snapshot and use its uids — the old node handle is no longer resolvable.","If it recurs on a live-looking element, the element is being replaced faster than you act; wait for a stable state (network idle, settled DOM) before snapshot+act.","Prefer re-acquiring over retrying the same handle; the nil object will not self-heal."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Go\nobj, err := dom.ResolveNode().WithBackendNodeID(id).Do(ctx)\nif err != nil {\n    return err\n}\nif obj == nil {\n    // node's JS wrapper is gone: re-snapshot to acquire a fresh handle\n    return errStaleHandle{id: id}\n}","preventionTips":["Treat resolve-node nil as 'stale handle': re-snapshot, never retry the same id.","Wait for settled DOM (no pending mutations/navigations) before acting on freshly-queried nodes.","Avoid acting on nodes inside frames mid-swap; site isolation makes their handles short-lived."],"tags":["browser","cdp","dom","race","stale-reference"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}