jackwener/OpenCLI · error · ArgumentError

Pass exactly one of --url <url>, --content <text>, or --file

Error message

Pass exactly one of --url <url>, --content <text>, or --file <path>

What it means

The add-source command handler throws this ArgumentError when none of the three mutually exclusive source modes (--url, --content, --file) was provided. The command requires exactly one source type; the modes array is built from the parsed values and rejected when its length is 0. (A sibling error with the same advice text plus '(got: ...)' fires when more than one is given.)

Source

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

    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.` },
        { name: 'title', help: 'Title for the text source (default "Text Source"). Ignored for --url and --file.' },
        { name: 'mime-type', help: 'Override the auto-detected MIME type when --file is given.' },
        { name: 'execute', type: 'boolean', help: 'Actually add the remote source to the NotebookLM notebook' },
    ],
    columns: ['notebook_id', 'source_id', 'kind', 'identifier', 'notebook_url'],
    func: async (page, kwargs) => {
        const notebookId = parseNotebooklmNotebookTarget(String(kwargs.notebook ?? ''));
        const url = parseSourceUrl(kwargs.url);
        const content = parseSourceText(kwargs.content);
        const filePath = typeof kwargs.file === 'string' && kwargs.file.trim() ? kwargs.file.trim() : '';
        const modes = [url ? 'url' : '', content !== null ? 'text' : '', filePath ? 'file' : ''].filter(Boolean);
        if (modes.length === 0) {
            throw new ArgumentError('Pass exactly one of --url <url>, --content <text>, or --file <path>');
        }
        if (modes.length > 1) {
            throw new ArgumentError('Pass exactly one of --url, --content, --file (got: ' + modes.join(' + ') + ')');
        }
        requireNotebooklmExecute(kwargs.execute, 'add a NotebookLM source');
        const title = parseSourceTitle(kwargs.title, 'Text Source');
        await ensureNotebooklmHome(page);
        await requireNotebooklmSession(page);
        if (filePath) {
            const file = readFileForUpload(filePath);
            const mime = inferMimeType(file.filename, kwargs['mime-type']);
            const registerRpc = await callNotebooklmRpc(page, NOTEBOOKLM_ADD_FILE_SOURCE_RPC_ID, buildRegisterFileSourceArgs(notebookId, file.filename));
            const sourceId = parseAddSourceResult(registerRpc.result, [notebookId]);
            if (!sourceId) {
                throw new CommandExecutionError('NotebookLM AddFileSource (o4cbdc) RPC returned no source id; cannot start file upload.');
            }
            await uploadFileViaDriveResumable(page, notebookId, sourceId, file.filename, file.base64, file.size);
            await verifyNotebooklmSourceAdded(page, notebookId, sourceId, 'add-source --file');

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Add exactly one of --url <url>, --content <text>, or --file <path> to the command.
  2. Check flag spelling — unrecognized/misspelled flags are silently ignored, leaving zero modes.
  3. If passing --content from a variable, confirm it is non-empty (an empty value counts as absent).
  4. Review the command in your script/alias to ensure the source argument wasn't dropped by quoting or expansion.

Example fix

// before
addSource({ notebook: 'abc123' }); // no source given
// after
addSource({ notebook: 'abc123', url: 'https://example.com/article' });
Defensive patterns

Strategy: validation

Validate before calling

const modes = [url, content, file].filter(v => v !== undefined && v !== null && String(v).trim() !== '');
if (modes.length !== 1) throw new Error('Pass exactly one of --url, --content, --file');

Type guard

function hasExactlyOneSource(o) {
  const n = ['url', 'content', 'file'].filter(k => o[k] !== undefined && o[k] !== null && String(o[k]).trim() !== '').length;
  return n === 1;
}

Try / catch

try {
  await addSource(args);
} catch (e) {
  if (e instanceof ArgumentError && e.message.includes('Pass exactly one of')) {
    console.error('Usage: add-source --notebook <id> (--url <u> | --content <t> | --file <p>)');
  } else throw e;
}

Prevention

When it happens

Trigger: Invoking add-source with only --notebook (no source flags at all); passing flags the parser didn't recognize so url/content/file all end up empty; an empty --content string (parsed to null via parseSourceText's undefined/null check) combined with missing --url/--file.

Common situations: Forgotten argument in scripted calls; shell eating an empty-quoted --content ''; typos like --ur1 or --file-path that the CLI ignores; running the command to 'test' connectivity without intending to add a source.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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