jackwener/OpenCLI · error · CommandExecutionError

NotebookLM RPC transport returned malformed response fields

Error message

NotebookLM RPC transport returned malformed response fields

What it means

fetchNotebooklmInPage evaluates an in-page fetch against NotebookLM's RPC endpoint and unwraps the evaluated result. Before returning it to callNotebooklmRpc, it validates the shape: ok must be boolean, status an integer, and body/requestUrl/finalUrl strings. If any field is missing or of the wrong type, the in-page bridge did not return a well-formed envelope, so this CommandExecutionError is thrown rather than propagating garbage downstream.

Source

Thrown at clis/notebooklm/rpc.js:214

      body: request.method === 'GET' ? undefined : request.body,
      credentials: 'include',
    });

    return {
      ok: response.ok,
      status: response.status,
      body: await response.text(),
      requestUrl,
      finalUrl: response.url,
    };
  })()`);
    }
    catch (error) {
        rethrowNotebooklmTransport(error, 'RPC transport');
    }
    const raw = requireNotebooklmObject(unwrapNotebooklmEvaluateResult(evaluated), 'RPC transport');
    if (typeof raw.ok !== 'boolean' || !Number.isInteger(raw.status) || typeof raw.body !== 'string' || typeof raw.requestUrl !== 'string' || typeof raw.finalUrl !== 'string') {
        throw new CommandExecutionError('NotebookLM RPC transport returned malformed response fields');
    }
    return {
        ok: raw.ok,
        status: raw.status,
        body: raw.body,
        requestUrl: raw.requestUrl,
        finalUrl: raw.finalUrl,
    };
}
export async function callNotebooklmRpc(page, rpcId, params, options = {}) {
    const auth = await getNotebooklmPageAuth(page);
    const requestBody = buildNotebooklmRpcBody(rpcId, params, auth.csrfToken);
    const authuser = auth.authuser || '';
    const url = NOTEBOOKLM_RPC_PATH +
        `?rpcids=${rpcId}&source-path=${encodeURIComponent(auth.sourcePath)}` +
        (authuser ? `&authuser=${encodeURIComponent(authuser)}` : '') +
        `&hl=${encodeURIComponent(options.hl ?? 'en')}` +
        `&f.sid=${encodeURIComponent(auth.sessionId)}&rt=c`;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the command after confirming the NotebookLM tab is fully loaded on a notebook/home URL (not a login or error page).
  2. Re-open the session with `opencli notebooklm open <notebook>` so the adapter attaches to a fresh page before retrying.
  3. Check for recent NotebookLM UI changes; update opencli to the latest version that matches the current in-page response shape.
  4. If reproducible, log the raw evaluated value from unwrapNotebooklmEvaluateResult to identify which field is malformed and file an issue.

Example fix

// before: calling RPC on a page that may have navigated
const res = await fetchNotebooklmInPage(page, method, body);
// after: guard the session state first
const state = await getNotebooklmPageState(page);
if (state.kind === null) await openNotebooklmSession(page);
const res = await fetchNotebooklmInPage(page, method, body);
Defensive patterns

Strategy: type-guard

Validate before calling

// before relying on the RPC envelope, verify the page is still on NotebookLM
const url = new URL(page.url());
if (!url.hostname.endsWith('notebooklm.google.com')) await reopenNotebooklmSession(page);

Type guard

function isValidRpcEnvelope(raw) {
  return !!raw && typeof raw === 'object' &&
    typeof raw.ok === 'boolean' &&
    Number.isInteger(raw.status) &&
    typeof raw.body === 'string' &&
    typeof raw.requestUrl === 'string' &&
    typeof raw.finalUrl === 'string';
}

Try / catch

try {
  const res = await fetchNotebooklmInPage(page, method, body);
  // use res
} catch (e) {
  if (e instanceof CommandExecutionError && e.message.includes('malformed response fields')) {
    await reopenNotebooklmSession(page); // recover by re-attaching a fresh page
  } else throw e;
}

Prevention

When it happens

Trigger: The browser evaluate step in unwrapNotebooklmEvaluateResult returns null/undefined (page navigated mid-call, script injected into a non-NotebookLM frame), the in-page wrapper returns a partial object, or the serialized response loses fields (e.g. status became a string, body undefined).

Common situations: The tab navigated away or reloaded while the RPC fetch was in flight; the adapter page is actually a Chrome error page or login interstitial rather than the app; an NotebookLM frontend update changed the in-page hook the wrapper relies on; the CDP evaluate returned a serialized object with dropped fields.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/064bc9744e18c3e7. Report an issue: GitHub.