{"record":{"id":"c02f218c9a45565d","repo":"jackwener/OpenCLI","slug":"notebooklm-action-succeeded-but-source-source","errorCode":null,"errorMessage":"NotebookLM ${action} succeeded but source ${sourceId} did not appear in the notebook's source list","messagePattern":"NotebookLM (.+?) succeeded but source (.+?) did not appear in the notebook's source list","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/notebooklm/utils.js","lineNumber":494,"sourceCode":"            throw new CommandExecutionError(`NotebookLM ${action} succeeded but the notebook ${notebookId} was not found in the post-write verification`);\n        }\n        return detail;\n    }\n    catch (error) {\n        if (error instanceof AuthRequiredError || error instanceof CommandExecutionError)\n            throw error;\n        throw new CommandExecutionError(`NotebookLM ${action} post-write verification failed: ${error?.message || error}`);\n    }\n}\nexport async function verifyNotebooklmSourceAdded(page, notebookId, sourceId, action) {\n    try {\n        const { detail, sources } = await getNotebooklmNotebookDetailById(page, notebookId);\n        if (!detail || detail.id !== notebookId) {\n            throw new CommandExecutionError(`NotebookLM ${action} succeeded but the notebook ${notebookId} was not found in the post-write verification`);\n        }\n        const matched = sources.find((s) => s.id === sourceId);\n        if (!matched) {\n            throw new CommandExecutionError(`NotebookLM ${action} succeeded but source ${sourceId} did not appear in the notebook's source list`);\n        }\n        return matched;\n    }\n    catch (error) {\n        if (error instanceof AuthRequiredError || error instanceof CommandExecutionError)\n            throw error;\n        throw new CommandExecutionError(`NotebookLM ${action} post-write verification failed: ${error?.message || error}`);\n    }\n}\nexport async function listNotebooklmSourcesViaRpc(page) {\n    const state = await getNotebooklmPageState(page);\n    if (state.kind !== 'notebook' || !state.notebookId)\n        return [];\n    const rpc = await callNotebooklmRpc(page, NOTEBOOKLM_NOTEBOOK_DETAIL_RPC_ID, [state.notebookId, null, [2], null, 0]);\n    return parseNotebooklmSourceListResult(rpc.result);\n}\nexport async function listNotebooklmHistoryViaRpc(page) {\n    const state = await getNotebooklmPageState(page);","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/notebooklm/utils.js#L476-L512","documentation":"After confirming the notebook exists, verifyNotebooklmSourceAdded searches the parsed source list for the given sourceId; if no source matches it throws this CommandExecutionError. It means the add-source action reported success, but the new source never appeared in the notebook's source list as observed through the detail RPC.","triggerScenarios":"Calling verifyNotebooklmSourceAdded when sources.find((s) => s.id === sourceId) finds nothing — the source list parsed from the detail RPC contains no entry with that id (add silently failed, wrong sourceId returned by the add call, or list parsing missed the new entry).","commonSituations":"NotebookLM rejected/async-processed the add so the source isn't in the list yet; the sourceId returned by the add action differs from what's stored; RPC schema change altered how sources are embedded in the detail payload; duplicate concurrent adds confusing state.","solutions":["Retry verification after a delay — NotebookLM may index new sources asynchronously","Compare the full parsed source list against the expected sourceId to see if the id differs (e.g. re-add and use the returned id)","Reload the notebook page and re-run verification to eliminate stale page state","Re-run the add-source action if the source genuinely never persisted","Check for library updates if NotebookLM changed the detail payload layout"],"exampleFix":"// before: immediate verify\nawait addNotebooklmSource(page, nb, src);\nawait verifyNotebooklmSourceAdded(page, nb, src.id, 'add-source');\n// after: eventual-consistency retry\nfor (let i = 0; i < 5; i++) {\n  try { await verifyNotebooklmSourceAdded(page, nb, src.id, 'add-source'); break; }\n  catch (e) {\n    if (!/did not appear in the notebook's source list/.test(e.message) || i === 4) throw e;\n    await page.wait(2);\n  }\n}","handlingStrategy":"retry","validationCode":"// sanity-check sourceId format before verification\nif (typeof sourceId !== 'string' || !sourceId.trim()) {\n  throw new Error('Invalid sourceId passed to verification');\n}","typeGuard":"function sourceInList(sources, sourceId) {\n  return Array.isArray(sources) && sources.some((s) => s?.id === sourceId);\n}","tryCatchPattern":"try {\n  await verifyNotebooklmSourceAdded(page, notebookId, sourceId, action);\n} catch (e) {\n  if (!/did not appear in the notebook's source list/.test(e.message) || attempts >= 4) throw e;\n  await page.wait(2); // NotebookLM may index sources asynchronously\n  // retry verification\n}","preventionTips":["Retry verification with backoff — new sources can appear with delay","Use the exact sourceId returned by the add-source call","Avoid duplicate concurrent add-source calls to the same notebook","Reload page state if verification repeatedly fails","Check for library updates if source list parsing changes"],"tags":["notebooklm","verification","eventual-consistency","scraping"],"backgroundTag":"post-write-verification-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}