Status: Active Last Updated: 2026-01-20
Common issues, known limitations, and workarounds for notebooklm-py.
First step: Run notebooklm auth check to diagnose auth issues:
notebooklm auth check # Quick local validation
notebooklm auth check --test # Full validation with network test
notebooklm auth check --json # Machine-readable output for CI/CDThis shows:
- Storage file location and validity
- Which cookies are present and their domains
- Whether NOTEBOOKLM_AUTH_JSON or NOTEBOOKLM_HOME is being used
- (With
--test) Whether token fetch succeeds
The client automatically refreshes CSRF tokens when authentication errors are detected. This happens transparently:
- When an RPC call fails with an auth error, the client:
- Fetches fresh CSRF token and session ID from the NotebookLM homepage
- Waits briefly to avoid rate limiting
- Retries the failed request once
- Concurrent requests share a single refresh task to prevent token thrashing
- If refresh fails, the original error is raised with the refresh failure as cause
This means most "CSRF token expired" errors resolve automatically.
Cause: Session cookies expired (happens every few weeks).
Note: Automatic token refresh handles CSRF/session ID expiration. This error only occurs when the underlying cookies (set during notebooklm login) have fully expired.
Solution:
notebooklm loginCause: CSRF token expired or couldn't be extracted.
Note: This error should rarely occur now due to automatic retry. If you see it, it likely means the automatic refresh also failed.
Solution (if auto-refresh fails):
# In Python - manual refresh
await client.refresh_auth()Or re-run notebooklm login if session cookies are also expired.
Cause: Google detecting automation and blocking login.
Solution:
- Delete the browser profile:
rm -rf ~/.notebooklm/browser_profile/ - Run
notebooklm loginagain - Complete any CAPTCHA or security challenges Google presents
- Ensure you're using a real mouse/keyboard (not pasting credentials via script)
Cause: The RPC method ID may have changed (Google updates these periodically), or:
- Rate limiting from Google
- Account quota exceeded
- API restrictions
Diagnosis:
# Enable debug mode to see what RPC IDs the server returns
NOTEBOOKLM_DEBUG_RPC=1 notebooklm <your-command>This will show output like:
DEBUG: Looking for RPC ID: Ljjv0c
DEBUG: Found RPC IDs in response: ['NewId123']
If the IDs don't match, the method ID has changed. Report the new ID in a GitHub issue.
Workaround:
- Wait 5-10 minutes and retry
- Try with fewer sources selected
- Reduce generation frequency
Cause: Google API returned an error, typically:
- Invalid parameters
- Resource not found
- Rate limiting
Solution:
- Check that notebook/source IDs are valid
- Add delays between operations (see Rate Limiting section)
Cause: Known issue with artifact generation under heavy load or rate limiting.
Workaround:
# Use --wait to see if it eventually succeeds
notebooklm generate audio --wait
# Or poll manually
notebooklm artifact poll <task_id>Cause: Generation may silently fail without error.
Solution:
- Wait 60 seconds and check
artifact list - Try regenerating with different/fewer sources
Cause: Known issue with native text file uploads.
Workaround: Use add_text instead:
# Instead of: notebooklm source add ./notes.txt
# Do:
notebooklm source add "$(cat ./notes.txt)"Or in Python:
content = Path("notes.txt").read_text()
await client.sources.add_text(nb_id, "My Notes", content)Cause: Files over ~20MB may exceed upload timeout.
Solution: Split large documents or use text extraction locally.
Symptoms:
- Source title shows "Fixing X.com Privacy Errors" or similar error message
- Generated content discusses browser extensions instead of the actual article
- Source appears to process successfully but contains wrong content
Cause: X.com (Twitter) has aggressive anti-scraping protections. When NotebookLM attempts to fetch the URL, it receives an error page or compatibility warning instead of the actual content.
Solution - Use bird CLI to pre-fetch content:
The bird CLI can fetch X.com content and output clean markdown:
# Step 1: Install bird (macOS/Linux)
brew install steipete/tap/bird
# Step 2: Fetch X.com content as markdown
bird read "https://x.com/username/status/1234567890" > article.md
# Step 3: Add the local markdown file to NotebookLM
notebooklm source add ./article.mdAlternative methods:
Using browser automation:
# If you have playwright/browser-use available
# Fetch content via browser and save as markdownManual extraction:
- Open the X.com post in a browser
- Copy the text content
- Save to a
.mdfile - Add the file to NotebookLM
Verification:
Always verify the source was correctly parsed:
notebooklm source list
# Check that the title matches the actual article, not an error messageIf the title contains error-related text, remove the source and use the pre-fetch method:
# Remove incorrectly parsed source
notebooklm source delete <source_id>
# Then re-add using the bird CLI method aboveOther affected sites:
- Some paywalled news sites
- Sites requiring JavaScript execution for content
- Sites with aggressive bot detection
Google enforces strict rate limits on the batchexecute endpoint.
Symptoms:
- RPC calls return
None RPCErrorwith IDR7cb6cUserDisplayableErrorwith code[3]
Best Practices:
CLI: Use --retry for automatic exponential backoff:
notebooklm generate audio --retry 3 # Retry up to 3 times on rate limit
notebooklm generate video --retry 5 # Works with all generate commandsPython:
import asyncio
# Add delays between intensive operations
for url in urls:
await client.sources.add_url(nb_id, url)
await asyncio.sleep(2) # 2 second delay
# Use exponential backoff on failures
async def retry_with_backoff(coro, max_retries=3):
for attempt in range(max_retries):
try:
return await coro
except RPCError:
wait = 2 ** attempt # 1, 2, 4 seconds
await asyncio.sleep(wait)
raise Exception("Max retries exceeded")Some features have daily/hourly quotas:
- Audio Overviews: Limited generations per day per account
- Video Overviews: More restricted than audio
- Deep Research: Consumes significant backend resources
Artifact downloads (audio, video, images) use httpx with cookies from your storage state. Playwright is NOT required for downloads—only for the initial notebooklm login.
If downloads fail with authentication errors:
Solution: Ensure your authentication is valid:
# Re-authenticate if cookies have expired
notebooklm login
# Or copy a fresh storage_state.json from another machineDownload URLs for audio/video are temporary:
- Expire within hours
- Always fetch fresh URLs before downloading:
# Get fresh artifact list before download
artifacts = await client.artifacts.list(nb_id)
audio = next(a for a in artifacts if a.kind == "audio")
# Use audio.url immediatelyPlaywright missing dependencies:
playwright install-deps chromiumNo display available (headless server):
- Browser login requires a display
- Authenticate on a machine with GUI, then copy
storage_state.json
Chromium not opening:
# Re-install Playwright browsers
playwright install chromiumSecurity warning about Chromium:
- Allow in System Preferences → Security & Privacy
CLI hangs indefinitely (issue #75):
On certain Windows environments (particularly when running inside Sandboxie or similar sandboxing software), the CLI may hang indefinitely at startup. This is caused by the default ProactorEventLoop blocking at the IOCP (I/O Completion Ports) layer.
Symptoms:
- CLI starts but never responds
- Process appears frozen with no output
- Happens consistently in sandboxed environments
Solution: The library automatically sets WindowsSelectorEventLoopPolicy at CLI startup to avoid this issue. If you're using the Python API directly and encounter hanging, add this before any async code:
import asyncio
import sys
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())Unicode encoding errors on non-English Windows (issue #75, #80):
Windows systems with non-English locales (Chinese cp950, Japanese cp932, etc.) may fail with UnicodeEncodeError when outputting Unicode characters like checkmarks (✓) or emojis.
Symptoms:
UnicodeEncodeError: 'cp950' codec can't encode character- Error occurs when printing status output with Rich tables
Solution: The library automatically sets PYTHONUTF8=1 at CLI startup. For Python API usage, either:
- Set
PYTHONUTF8=1environment variable before running - Run Python with
-X utf8flag:python -X utf8 your_script.py
Path issues:
- Use forward slashes or raw strings:
r"C:\path\to\file" - Ensure
~expansion works: usePath.home()in Python
Browser opens in Windows, not WSL:
- This is expected behavior
- Storage file is saved in WSL filesystem
notebooklm-py provides structured logging to help debug issues.
Environment Variables:
| Variable | Default | Effect |
|---|---|---|
NOTEBOOKLM_LOG_LEVEL |
WARNING |
Set to DEBUG, INFO, WARNING, or ERROR |
NOTEBOOKLM_DEBUG_RPC |
(unset) | Legacy: Set to 1 to enable DEBUG level |
When to use each level:
# WARNING (default): Only show warnings and errors
notebooklm list
# INFO: Show major operations (good for scripts/automation)
NOTEBOOKLM_LOG_LEVEL=INFO notebooklm source add https://example.com
# Output:
# 14:23:45 INFO [notebooklm._sources] Adding URL source: https://example.com
# DEBUG: Show all RPC calls with timing (for troubleshooting API issues)
NOTEBOOKLM_LOG_LEVEL=DEBUG notebooklm list
# Output:
# 14:23:45 DEBUG [notebooklm._core] RPC LIST_NOTEBOOKS starting
# 14:23:46 DEBUG [notebooklm._core] RPC LIST_NOTEBOOKS completed in 0.842sProgrammatic use:
import logging
import os
# Set before importing notebooklm
os.environ["NOTEBOOKLM_LOG_LEVEL"] = "DEBUG"
from notebooklm import NotebookLMClient
# Now all notebooklm operations will log at DEBUG levelStart simple to isolate issues:
# 1. Can you list notebooks?
notebooklm list
# 2. Can you create a notebook?
notebooklm create "Test"
# 3. Can you add a source?
notebooklm source add "https://example.com"If you suspect network issues:
import httpx
# Test basic connectivity
async with httpx.AsyncClient() as client:
r = await client.get("https://notebooklm.google.com")
print(r.status_code) # Should be 200 or 302- Check this troubleshooting guide
- Search existing issues
- Open a new issue with:
- Command/code that failed
- Full error message
- Python version (
python --version) - Library version (
notebooklm --version) - Operating system