{"record":{"id":"68412e67aecdc834","repo":"jackwener/OpenCLI","slug":"pixiv-image-download-did-not-create-a-valid-file","errorCode":null,"errorMessage":"Pixiv image download did not create a valid file: ${file.filename}","messagePattern":"Pixiv image download did not create a valid file: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/bookmark-download.js","lineNumber":109,"sourceCode":"\nasync function commitIllustPlan(plan, cookies) {\n  const parent = path.dirname(plan.finalPath);\n  let staging;\n  try {\n    fs.mkdirSync(parent, { recursive: true });\n    staging = fs.mkdtempSync(path.join(parent, `.opencli-${plan.illustId}-`));\n    for (const file of plan.files) {\n      const destination = path.join(staging, file.filename);\n      const result = await httpDownload(file.url, destination, {\n        cookies,\n        headers: { Referer: 'https://www.pixiv.net/' },\n        timeout: 60000,\n        includeContentType: true,\n      });\n      validateImageDownload(result, file);\n      const stat = fs.lstatSync(destination);\n      if (stat.isSymbolicLink() || !stat.isFile() || stat.size <= 0) {\n        throw new CommandExecutionError(`Pixiv image download did not create a valid file: ${file.filename}`);\n      }\n    }\n    if (pixivPathEntryExists(plan.finalPath)) {\n      throw new CommandExecutionError(`Refusing to overwrite existing Pixiv download: ${plan.finalPath}`);\n    }\n    fs.renameSync(staging, plan.finalPath);\n    return plan.finalPath;\n  } catch (error) {\n    if (staging) {\n      try { fs.rmSync(staging, { recursive: true, force: true }); } catch {}\n    }\n    for (const directory of plan.createdDirs) {\n      try { fs.rmdirSync(directory); } catch {}\n    }\n    if (error instanceof CommandExecutionError) throw error;\n    throw new CommandExecutionError(`Pixiv illustration ${plan.illustId} download failed: ${error?.message || error}`);\n  }\n}","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/bookmark-download.js#L91-L127","documentation":"After a successful-looking download and validateImageDownload, commitIllustPlan lstats the staged file and requires it to be a real, non-symlink, non-empty file. This CommandExecutionError is thrown when the staged path is missing, a symlink, a directory, or zero bytes, meaning the downloader reported success but did not actually materialize the image. It is a post-download integrity guard.","triggerScenarios":"fs.lstatSync(destination) on the staging path returns a stat where stat.isSymbolicLink(), !stat.isFile(), or stat.size <= 0, right after validateImageDownload passed for file.filename.","commonSituations":"The download tool wrote to a different working directory than expected; a symlink-hijacking or disk issue replaced the file; the download command reported success but wrote 0 bytes on a flaky network or rate-limited response; antivirus/cleanup removed the staged file mid-run.","solutions":["Re-run the download; transient empty responses are the most common cause","Check free disk space and that the staging directory is writable","Inspect the staging path for a symlink or directory and remove anything unexpected","Verify the download command actually writes to the expected destination path (no cwd/path mismatch)","Update the download tool/driver if zero-byte 'successful' downloads recur"],"exampleFix":"// before: trusting validateImageDownload alone\nvalidateImageDownload(result, file);\n// after: also fail fast on empty responses before committing\nvalidateImageDownload(result, file);\nif (result.size <= 0) throw new CommandExecutionError(`empty body for ${file.filename}`);","handlingStrategy":"validation","validationCode":"const stat = fs.lstatSync(destination, { throwIfNoEntry: false });\nif (!stat || stat.isSymbolicLink() || !stat.isFile() || stat.size <= 0) {\n  throw new Error(`staged file invalid before commit: ${destination}`);\n}","typeGuard":"function isRegularNonEmptyFile(p) {\n  try {\n    const s = fs.lstatSync(p);\n    return s.isFile() && !s.isSymbolicLink() && s.size > 0;\n  } catch { return false; }\n}","tryCatchPattern":"try {\n  fs.lstatSync(destination);\n} catch (err) {\n  if (err.code === 'ENOENT') {\n    console.warn(`Download produced no file for ${file.filename}; retrying`);\n    return retryDownload(file);\n  }\n  throw err;\n}","preventionTips":["Always lstat the staged path before renaming into place","Run downloads to a dedicated staging dir you control","Monitor free disk space before large archives","Alert on result.size <= 0 even when success === true"],"tags":["pixiv","download","filesystem","integrity"],"backgroundTag":"empty-or-invalid-download","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}