{"record":{"id":"c5b543f69196ca3e","repo":"jackwener/OpenCLI","slug":"file-must-be-a-readable-text-file-path","errorCode":null,"errorMessage":"File must be a readable text file: ${path}","messagePattern":"File must be a readable text file: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/_atlassian/shared.js","lineNumber":301,"sourceCode":"    return n;\n}\n\nexport function requireExecute(args, commandName) {\n    if (args.execute !== true) {\n        throw new ArgumentError(`${commandName} requires --execute to perform a remote write`);\n    }\n}\n\nexport async function readUtf8File(filePath) {\n    const path = requireString(filePath, '--file');\n    let fileStat;\n    try {\n        fileStat = await stat(path);\n    } catch {\n        throw new ArgumentError(`File not found: ${path}`);\n    }\n    if (!fileStat.isFile()) {\n        throw new ArgumentError(`File must be a readable text file: ${path}`);\n    }\n    let raw;\n    try {\n        raw = await readFile(path);\n    } catch {\n        throw new ArgumentError(`File could not be read: ${path}`);\n    }\n    try {\n        return new TextDecoder('utf-8', { fatal: true }).decode(raw);\n    } catch {\n        throw new ArgumentError(`File could not be decoded as UTF-8 text: ${path}`);\n    }\n}\n\nexport function htmlEscape(value) {\n    return String(value ?? '')\n        .replace(/&/g, '&amp;')\n        .replace(/</g, '&lt;')","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/_atlassian/shared.js#L283-L319","documentation":"After stat() succeeds, readUtf8File checks fileStat.isFile() to ensure the target is a regular file, not a directory, FIFO, socket, or device. If it is not a regular file it throws ArgumentError 'File must be a readable text file: <path>'.","triggerScenarios":"Passing a directory path (e.g. --file ./docs) or a special file (named pipe, /dev/ node) to readUtf8File.","commonSituations":"Pointing --file at a folder instead of a file by mistake; shell glob or variable expansion resolving to a directory; passing a device or procfs path expecting it to behave like a text file.","solutions":["Pass the path to a regular file, not a directory or special file.","Check the target with `file <path>` or `stat -c %F <path>` to confirm it is a regular file.","If you meant to send several files, iterate over the directory and pass each file individually."],"exampleFix":"// before\ncli confluence create --file ./pages/\n// after\ncli confluence create --file ./pages/index.md","handlingStrategy":"validation","validationCode":"const s = await stat(p);\nif (!s.isFile()) throw new Error(`--file must be a regular file, got: ${p}`);","typeGuard":"const isRegularFile = async (p) => { try { return (await stat(p)).isFile(); } catch { return false; } };","tryCatchPattern":"try {\n  const text = await readUtf8File(p);\n} catch (err) {\n  if (err.name === 'ArgumentError' && err.message.includes('readable text file')) {\n    console.error(`${p} is not a regular file; pass a file, not a directory or device.`);\n  }\n  throw err;\n}","preventionTips":["Verify with `file <path>` / stat that targets are regular files.","Expand globs to concrete files before passing them.","Never point --file at directories; loop over entries instead."],"tags":["filesystem","file-type","argument-validation","cli"],"backgroundTag":"file-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}