jackwener/OpenCLI · error · AuthRequiredError

Google SSO cookies (SID + SAPISID) missing

Error message

Google SSO cookies (SID + SAPISID) missing

What it means

verifyNotebookLmIdentity first checks the browser context for Google SSO cookies SID and SAPISID. If either is absent it throws AuthRequiredError for the notebooklm domain, because NotebookLM API/RPC calls cannot be authenticated without them.

Source

Thrown at clis/notebooklm/auth.js:14

import { AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors';
import { registerSiteAuthCommands } from '../_shared/site-auth.js';
import { NOTEBOOKLM_DOMAIN, NOTEBOOKLM_HOME_URL } from './shared.js';
import { unwrapNotebooklmEvaluateResult } from './rpc.js';

async function hasNotebookLmSsoCookies(page) {
  const cookies = await page.getCookies({ url: NOTEBOOKLM_HOME_URL });
  const names = new Set(cookies.map(c => c.name));
  return names.has('SID') && names.has('SAPISID');
}

async function verifyNotebookLmIdentity(page) {
  if (!await hasNotebookLmSsoCookies(page)) {
    throw new AuthRequiredError(NOTEBOOKLM_DOMAIN, 'Google SSO cookies (SID + SAPISID) missing');
  }
  await page.goto(NOTEBOOKLM_HOME_URL);
  await page.wait(3);
  const probe = unwrapNotebooklmEvaluateResult(await page.evaluate(`
    (() => {
      if (/accounts\\.google\\.com\\/ServiceLogin/.test(location.href) || /accounts\\.google\\.com\\/signin/i.test(location.href)) {
        return { kind: 'auth', detail: 'NotebookLM redirected to Google sign-in' };
      }
      const acctEl = document.querySelector('a[aria-label^="Google Account:"], a[aria-label*="Google 账号:"]');
      if (!acctEl) {
        return { kind: 'auth', detail: 'NotebookLM missing Google Account button' };
      }
      const label = acctEl.getAttribute('aria-label') || '';
      const nameMatch = label.match(/Google Account:\\s*([^\\n\\(]+?)(?:\\s*\\n|\\s*\\()/i) ||
                        label.match(/Google 账号:\\s*([^\\n\\(]+?)(?:\\s*\\n|\\s*\\()/i);
      const name = nameMatch ? nameMatch[1].trim() : '';
      const authuserMatch = location.href.match(/[?&]authuser=(\\d+)/);
      const authuser = authuserMatch ? Number(authuserMatch[1]) : 0;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Run the site's login flow (e.g. `notebooklm login`) and complete Google SSO interactively.
  2. Point the CLI at a browser profile that is already logged into Google.
  3. Re-login if cookies expired; SID/SAPISID must both be present in the cookie jar for accounts.google.com / notebooklm context.

Example fix

// before
runCommand('notebooklm create --title Notes')
// after
runCommand('notebooklm login')  // completes SSO, sets SID + SAPISID
runCommand('notebooklm create --title Notes')
Defensive patterns

Strategy: try-catch

Validate before calling

const cookies = await browser.cookies.getAll({ domain: 'google.com' });
if (!cookies.some(c => c.name === 'SID') || !cookies.some(c => c.name === 'SAPISID')) await runLogin();

Type guard

function hasSsoCookies(cookies) {
  const names = new Set(cookies.map(c => c.name));
  return names.has('SID') && names.has('SAPISID');
}

Try / catch

try {
  await notebooklm.create({ title });
} catch (e) {
  if (String(e.message).includes('Google SSO cookies')) {
    await notebooklmLogin(); // interactive SSO
    return notebooklm.create({ title });
  }
  throw e;
}

Prevention

When it happens

Trigger: Running any notebooklm command (or a poll/quick check) when the browser profile was never logged into Google, cookies were cleared, or a different profile (authuser) is active.

Common situations: Fresh automation container with no logged-in profile; incognito session; Google expired/revoked cookies; running headless before an initial interactive `notebooklm login`.

Related errors


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