{"record":{"id":"b5da2f2f80dd6e03","repo":"jackwener/OpenCLI","slug":"weixin-create-draft-cover-image-is-not-a-file-a","errorCode":null,"errorMessage":"weixin create-draft cover-image is not a file: ${absPath}","messagePattern":"weixin create-draft cover-image is not a file: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/weixin/create-draft.js","lineNumber":44,"sourceCode":"}\n\nfunction isRecoverableFileInputError(error) {\n    const message = error instanceof Error ? error.message : String(error);\n    return /unknown action|not supported|not[-\\s]?allowed|notallowederror/i.test(message);\n}\n\nfunction resolveCoverImage(rawPath) {\n    const value = String(rawPath ?? '').trim();\n    if (!value) throw new ArgumentError('weixin create-draft cover-image cannot be empty');\n    const absPath = path.resolve(value);\n    let stat;\n    try {\n        stat = fs.statSync(absPath);\n    } catch {\n        throw new ArgumentError(`weixin create-draft cover-image does not exist: ${absPath}`);\n    }\n    if (!stat.isFile()) {\n        throw new ArgumentError(`weixin create-draft cover-image is not a file: ${absPath}`);\n    }\n    const extension = path.extname(absPath).toLowerCase();\n    const mimeType = IMAGE_MIME_TYPES.get(extension);\n    if (!mimeType) {\n        throw new ArgumentError('weixin create-draft cover-image must be JPEG, PNG, GIF, or WebP');\n    }\n    return { absPath, fileName: path.basename(absPath), mimeType };\n}\n\nasync function navigateToEditor(page) {\n    await page.goto(WEIXIN_HOME);\n    await page.wait(3);\n    const token = await evaluate(page, `(window.location.href.match(/token=(\\\\d+)/)||[])[1]`);\n    if (!token) {\n        throw new AuthRequiredError(WEIXIN_DOMAIN, 'Please log in to the WeChat Official Account platform and retry.');\n    }\n    await page.goto(`https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit_v2&action=edit&isNew=1&type=77&token=${token}&lang=zh_CN`);\n    await page.wait(4);","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weixin/create-draft.js#L26-L62","documentation":"The path exists but stat.isFile() is false — the cover image points to a directory or special file. The library rejects it with this ArgumentError since the WeChat draft API needs an actual image file to upload.","triggerScenarios":"Passing a directory path as cover-image; passing a device/fifo/socket path; on some setups a symlink pointing at a directory (statSync follows symlinks).","commonSituations":"Pointing cover-image at an assets folder instead of a file; shell glob expanding oddly; variable holding a directory from upstream config.","solutions":["Point cover-image at an actual image file, not a directory.","If using a symlink, confirm it resolves to a regular file.","Print/inspect the resolved path in the error to see what was actually passed."],"exampleFix":"// before\ncoverImage: './assets'\n// after\ncoverImage: './assets/cover.jpg'","handlingStrategy":"validation","validationCode":"const st = fs.statSync(path.resolve(coverImage));\nif (!st.isFile()) throw new Error('cover-image must be a regular file, not a directory');","typeGuard":"function isRegularFile(p) {\n  try { return fs.statSync(p).isFile(); } catch { return false; }\n}","tryCatchPattern":"try {\n  await createDraft({ coverImage });\n} catch (err) {\n  if (err instanceof ArgumentError && err.message.includes('is not a file')) {\n    console.error('coverImage must point to a file, not a directory');\n  } else throw err;\n}","preventionTips":["Never point cover-image at a directory","Validate symlinks resolve to files","Sanitize upstream config values","Resolve globs to concrete file paths before calling"],"tags":["weixin","argument-error","filesystem","not-a-file"],"backgroundTag":"file-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}