jackwener/OpenCLI · error · CommandExecutionError

NotebookLM file upload failed:

Error message

NotebookLM file upload failed: 

What it means

uploadFileViaDriveResumable throws this CommandExecutionError when the in-page Drive resumable upload script returns no result or carries an error field; the message appends result.error or the literal 'unknown error'. This is the point where a NotebookLM file upload executed inside the browser page (via page.evaluate) failed — network, auth, quota, or a JS exception inside the page script.

Source

Thrown at clis/notebooklm/add-source.js:182

          'X-Goog-Upload-Offset': '0',
          'X-Goog-AuthUser': ${JSON.stringify(authuser)},
        },
        body: bytes,
      });
      if (!uploadRes.ok) {
        const status = uploadRes.headers.get('X-Goog-Upload-Status') || '';
        const text = (await uploadRes.text()).slice(0, 400);
        return { error: 'upload failed HTTP ' + uploadRes.status + (status ? ' upload-status=' + status : '') + (text ? ' body=' + text : '') };
      }
      return { ok: true, status: uploadRes.status };
    } catch (e) {
      return { error: 'upload exception: ' + ((e && e.message) || String(e)) };
    }
  })()`;
    const raw = await page.evaluate(script);
    const result = raw && typeof raw === 'object' && 'data' in raw && 'session' in raw ? raw.data : raw;
    if (!result || result.error) {
        throw new CommandExecutionError('NotebookLM file upload failed: ' + (result?.error || 'unknown error'));
    }
    return result;
}

cli({
    site: NOTEBOOKLM_SITE,
    name: 'add-source',
    access: 'write',
    description: 'Add a URL, text, or local file source to an existing NotebookLM notebook',
    domain: NOTEBOOKLM_DOMAIN,
    strategy: Strategy.COOKIE,
    browser: true,
    navigateBefore: false,
    args: [
        { name: 'notebook', positional: true, required: true, help: 'Notebook id from `notebooklm list` or full notebook URL' },
        { name: 'url', help: 'Source URL to add (http/https). Pass exactly one of --url, --content, --file.' },
        { name: 'content', help: 'Raw text content to add as a Text source (max 10 MB).' },
        { name: 'file', help: `Local file path to upload as a source (max ${MAX_FILE_SOURCE_BYTES} bytes; pdf / txt / md / html / docx / etc.). Uses Google Drive's 3-step resumable upload protocol.` },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the appended detail after 'NotebookLM file upload failed: ' to identify the concrete cause (exception text vs Drive error).
  2. Re-authenticate / refresh the browser session if the error indicates auth or a 401/403.
  3. Retry the upload for transient network errors; consider chunked resumable retries.
  4. Verify the file passes the size checks (see readFileForUpload) and that the site script hasn't changed; update the automation if Drive endpoints moved.

Example fix

// before
const raw = await page.evaluate(script); // throws vague failure
// after
const raw = await page.evaluate(script);
if (!raw) throw new CommandExecutionError('upload returned no result — check session/login state');
if (raw.error?.includes('401') || raw.error?.includes('auth')) await relogin();
Defensive patterns

Strategy: try-catch

Validate before calling

// before uploading: confirm session and file constraints
const stat = fs.statSync(filePath);
if (!stat.isFile() || stat.size > MAX_FILE_SOURCE_BYTES) throw new Error('File unsuitable for upload');
// ensure the browser session is logged in before invoking
await ensureNotebooklmSession(page);

Type guard

function isUploadResult(r) { return r && typeof r === 'object' && !('error' in r && r.error); }

Try / catch

try {
  await addSource({ file: filePath });
} catch (e) {
  if (e instanceof CommandExecutionError && e.message.startsWith('NotebookLM file upload failed')) {
    const detail = e.message.slice('NotebookLM file upload failed: '.length);
    if (/401|403|auth/i.test(detail)) await relogin(page);
    else if (/network|timeout/i.test(detail)) await retryWithBackoff(() => addSource({ file: filePath }));
    else console.error('Upload failed:', detail);
  } else throw e;
}

Prevention

When it happens

Trigger: The page.evaluate upload script throws (caught and returned as 'upload exception: ...'), the Drive resumable session returns a non-2xx, the browser session is logged out, or the result object is missing/null so the fallback 'unknown error' is used.

Common situations: Expired NotebookLM/Google session cookies mid-automation; Drive API quota or CORS/network failures inside the page; oversized files timing out during the resumable upload; site DOM/script changes breaking the injected evaluate script.

Related errors


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