{"record":{"id":"32899e8d63398de8","repo":"jackwener/OpenCLI","slug":"no-downloadable-media-found-on-this-note","errorCode":null,"errorMessage":"No downloadable media found on this note.","messagePattern":"No downloadable media found on this note\\.","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/xiaohongshu/download.js","lineNumber":234,"sourceCode":"    ],\n    columns: ['index', 'type', 'status', 'size'],\n    func: async (page, kwargs) => {\n        const rawInput = String(kwargs['note-id']);\n        const output = kwargs.output;\n        const noteId = parseNoteId(rawInput);\n        await page.goto(buildNoteUrl(rawInput, { allowShortLink: true, commandName: 'xiaohongshu download' }));\n        await page.wait({ time: 1 + Math.random() * 2 });\n        const data = await page.evaluate(buildDownloadExtractJs(noteId));\n        if (data?.securityBlock) {\n            throw new CliError('SECURITY_BLOCK', 'Xiaohongshu security block: the note detail page was blocked by risk control.', /^https?:\\/\\//.test(rawInput)\n                ? 'The page may be temporarily restricted. Try again later or from a different session.'\n                : 'Try using a full URL from search results (with xsec_token) instead of a bare note ID.');\n        }\n        if (!data || typeof data !== 'object' || !Array.isArray(data.media)) {\n            throw new CommandExecutionError('Xiaohongshu media extraction returned malformed payload.');\n        }\n        if (data.media.length === 0) {\n            throw new EmptyResultError('xiaohongshu download', 'No downloadable media found on this note.');\n        }\n        // Extract cookies for authenticated downloads\n        const cookies = formatCookieHeader(await page.getCookies({ domain: 'xiaohongshu.com' }));\n        const resolvedNoteId = typeof data.noteId === 'string' && data.noteId.trim()\n            ? data.noteId.trim()\n            : noteId;\n        return downloadMedia(data.media, {\n            output,\n            subdir: resolvedNoteId,\n            cookies,\n            filenamePrefix: resolvedNoteId,\n            timeout: 60000,\n        });\n    },\n});\n","sourceCodeStart":216,"sourceCodeEnd":250,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/download.js#L216-L250","documentation":"EmptyResultError thrown when extraction succeeded (valid payload with a `media` array) but the array is empty — the note detail page contained no downloadable media. This typically means the note is media-less (text-only in a way the extractor doesn't capture), the media failed to load, or the extractor's media selectors missed the actual media elements.","triggerScenarios":"Calling `xiaohongshu download` on a note whose page renders with zero detected media elements: a note type the extractor does not support, lazy-loaded media not yet in DOM at evaluate time, or extractor selectors missing media after a DOM change.","commonSituations":"Downloading a text-only or unsupported note type; scraping a note where images load lazily and evaluate ran too early; an extractor update lagging a Xiaohongshu DOM change.","solutions":["Verify the note actually has images/video by opening it in a browser; if yes, the extractor selectors are stale — update buildDownloadExtractJs.","Increase the wait before evaluate so lazy-loaded media is present in the DOM.","Confirm the note ID/URL points to the intended note.","Handle EmptyResultError explicitly and skip such notes in batch jobs."],"exampleFix":"// before\ntry { await downloadNote(url); } catch (e) { throw e; }\n// after\ntry { await downloadNote(url); }\ncatch (e) {\n  if (e.name === 'EmptyResultError') return skip(url); // no media on note\n  throw e;\n}","handlingStrategy":"validation","validationCode":"// Confirm the note actually has media before downloading (or treat empty as expected)\nconst noteMeta = await fetchNoteMeta(noteUrl); // page or API returning media count\nif (!noteMeta || noteMeta.mediaCount === 0) {\n  console.log('note has no media; skipping download');\n}","typeGuard":"function hasDownloadableMedia(data) { return Array.isArray(data?.media) && data.media.length > 0; }","tryCatchPattern":"try {\n  await cli.run('xiaohongshu download', { input: url });\n} catch (err) {\n  if (err instanceof EmptyResultError) return null; // legitimately no media\n  throw err;\n}","preventionTips":["Open the note in a browser to confirm it actually contains images/video before treating empty results as a bug.","Add a longer settle wait so lazy-loaded media is in the DOM at evaluate time.","Skip EmptyResultError notes gracefully in batch pipelines instead of failing the job.","Update extractor media selectors if many known-media notes return empty."],"tags":["empty-result","extraction","media","web-automation"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}