jackwener/OpenCLI · error · CliError

NOTEBOOKLM_TOKENS

NOTEBOOKLM_TOKENS

Error message

NOTEBOOKLM_TOKENS

What it means

extractNotebooklmPageAuthFromHtml scrapes the CSRF token (SNlM0e) and session id (FdrFJe) out of the served NotebookLM page HTML. If neither the page HTML nor preferredTokens yields a non-empty value for both, it throws CliError with code NOTEBOOKLM_TOKENS. The library refuses to sign batchexecute RPCs without these tokens because every call would fail server-side.

Source

Thrown at clis/notebooklm/rpc.js:32

    if (error instanceof CliError)
        throw error;
    throw new CommandExecutionError(`NotebookLM ${label} failed: ${error?.message || error}`);
}

export function unwrapNotebooklmEvaluateResult(payload) {
    if (payload && typeof payload === 'object' && !Array.isArray(payload) && 'session' in payload && 'data' in payload) {
        return payload.data;
    }
    return payload;
}

export function extractNotebooklmPageAuthFromHtml(html, sourcePath = '/', preferredTokens) {
    const csrfMatch = html.match(/"SNlM0e":"([^"]+)"/);
    const sessionMatch = html.match(/"FdrFJe":"([^"]+)"/);
    const csrfToken = preferredTokens?.csrfToken?.trim() || (csrfMatch ? csrfMatch[1] : '');
    const sessionId = preferredTokens?.sessionId?.trim() || (sessionMatch ? sessionMatch[1] : '');
    if (!csrfToken || !sessionId) {
        throw new CliError('NOTEBOOKLM_TOKENS', 'NotebookLM page tokens were not found in the current page HTML', 'Open the NotebookLM notebook page in Chrome, wait for it to finish loading, then retry with --verbose if it still fails.');
    }
    return { csrfToken, sessionId, sourcePath: sourcePath || '/', authuser: preferredTokens?.authuser ?? '' };
}
async function probeNotebooklmPageAuth(page) {
    let evaluated;
    try {
        evaluated = await page.evaluate(`(() => {
    const wiz = window.WIZ_global_data || {};
    const html = document.documentElement.innerHTML;
    const authMatch = (location.search || '').match(/[?&]authuser=(\\d+)/);
    const pathMatch = (location.pathname || '').match(/^\\/u\\/(\\d+)\\//);
    return {
      html,
      sourcePath: location.pathname || '/',
      readyState: document.readyState || '',
      csrfToken: typeof wiz.SNlM0e === 'string' ? wiz.SNlM0e : '',
      sessionId: typeof wiz.FdrFJe === 'string' ? wiz.FdrFJe : '',
      authuser: authMatch ? authMatch[1] : (pathMatch ? pathMatch[1] : ''),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Open the actual NotebookLM notebook page in Chrome, wait for it to finish loading, then retry
  2. Retry with --verbose to dump the HTML and confirm which token is missing
  3. Pass --authuser matching the logged-in profile so the app page (not a redirect) is served
  4. Update the CLI if NotebookLM changed its internal token serialization

Example fix

// before (parsing a wrong page)
const html = await page.content(); // login interstitial
const tokens = extractNotebooklmPageAuthFromHtml(html);
// after (verify you are on the app page first)
const html = await page.content();
if (!/"SNlM0e":"[^"]+"/.test(html)) throw new Error('not on NotebookLM app page; complete login first');
const tokens = extractNotebooklmPageAuthFromHtml(html);
Defensive patterns

Strategy: validation

Validate before calling

function hasNotebooklmTokens(html) {
  return /"SNlM0e":"[^"]+"/.test(html) && /"FdrFJe":"[^"]+"/.test(html);
}
// call before extractNotebooklmPageAuthFromHtml
if (!hasNotebooklmTokens(html)) throw new Error('page HTML lacks NotebookLM tokens; open the notebook page fully loaded');

Type guard

function isTokenSet(t) {
  return typeof t?.csrfToken === 'string' && t.csrfToken.length > 0 &&
         typeof t?.sessionId === 'string' && t.sessionId.length > 0;
}

Try / catch

try {
  const tokens = extractNotebooklmPageAuthFromHtml(html);
} catch (e) {
  if (e.code === 'NOTEBOOKLM_TOKENS') {
    console.error('Open the NotebookLM notebook page in Chrome, wait for full load, then retry.');
  } else throw e;
}

Prevention

When it happens

Trigger: extractNotebooklmPageAuthFromHtml receives HTML without "SNlM0e":"..." or "FdrFJe":"..." and preferredTokens lacks csrfToken or sessionId (empty or whitespace-only).

Common situations: Page captured is a Google login/consent interstitial instead of the notebook app; NotebookLM served an error page; NotebookLM renamed its internal token keys in a frontend update; --authuser/--hl query params landed on a variant page missing tokens.

Related errors


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