{"record":{"id":"ee7b27b9171bb191","repo":"wavetermdev/waveterm","slug":"reading-file-s-w","errorCode":null,"errorMessage":"reading file %s: %w","messagePattern":"reading file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/wsh/cmd/wshcmd-ai.go","lineNumber":132,"sourceCode":"\t\t\t\treturn fmt.Errorf(\"getting absolute path for %s: %w\", filePath, err)\n\t\t\t}\n\n\t\t\tif fileInfo.IsDir() {\n\t\t\t\tresult, err := fileutil.ReadDir(filePath, 500)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"reading directory %s: %w\", filePath, err)\n\t\t\t\t}\n\t\t\t\tjsonData, err := json.Marshal(result)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"marshaling directory listing for %s: %w\", filePath, err)\n\t\t\t\t}\n\t\t\t\tdata = jsonData\n\t\t\t\tfileName = absPath\n\t\t\t\tmimeType = \"directory\"\n\t\t\t} else {\n\t\t\t\tdata, err = os.ReadFile(filePath)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"reading file %s: %w\", filePath, err)\n\t\t\t\t}\n\t\t\t\tfileName = absPath\n\t\t\t\tmimeType = detectMimeType(data)\n\t\t\t}\n\t\t}\n\n\t\tisPDF := mimeType == \"application/pdf\"\n\t\tisImage := strings.HasPrefix(mimeType, \"image/\")\n\t\tisDirectory := mimeType == \"directory\"\n\n\t\tif !isPDF && !isImage && !isDirectory {\n\t\t\tmimeType = \"text/plain\"\n\t\t\tif utilfn.ContainsBinaryData(data) {\n\t\t\t\treturn fmt.Errorf(\"file %s contains binary data and cannot be uploaded as text\", fileName)\n\t\t\t}\n\t\t}\n\n\t\tmaxSize, sizeStr := getMaxFileSize(mimeType)","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/cmd/wsh/cmd/wshcmd-ai.go#L114-L150","documentation":"Wraps os.ReadFile(filePath) failure when a `wsh ai` argument is a regular file. os.Stat succeeded but the actual read failed — most commonly permission denied on the file itself, an I/O error, or the file being removed between Stat and Read. The wrapped error (*fs.PathError with EBADF/EACCES/EIO/EISDIR etc.) is preserved via %w.","triggerScenarios":"`wsh ai <file>` where the file exists but is not readable by the current user (Stat can succeed via parent dir +x without file r), the file is a special device/fifo that fails on read, it was deleted between Stat and ReadFile, or hardware/IO errors occur.","commonSituations":"Reading logs owned by root as a normal user; attaching files on a dying disk or full/failed mount; scripts racing with file deletion; attaching /dev files by mistake.","solutions":["Check readability: `cat <file> >/dev/null`; fix with chmod/chown or use sudo to copy it somewhere readable first.","Re-check the file still exists (`ls -l <file>`) — handle deletion races in scripts.","If it's a fifo/device/symlink to one, attach a regular file (e.g. `cp` or dump contents to a temp file first).","Investigate disk/mount health if the wrapped error is EIO."],"exampleFix":"// before\n$ wsh ai /var/log/syslog\n// error: reading file /var/log/syslog: open ...: permission denied\n// after\n$ sudo cat /var/log/syslog | wsh ai -","handlingStrategy":"validation","validationCode":"for f in \"$@\"; do\n  if [ -f \"$f\" ] && ! [ -r \"$f\" ]; then\n    echo \"file not readable: $f\" >&2; exit 1\n  fi\ndone","typeGuard":null,"tryCatchPattern":"if err := runAI(args); err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) {\n        switch {\n        case errors.Is(perr.Err, syscall.EACCES):\n            return fmt.Errorf(\"no read permission on %q; chmod/copy first\", perr.Path)\n        case errors.Is(perr.Err, syscall.EIO):\n            return fmt.Errorf(\"I/O error reading %q; check disk/mount health\", perr.Path)\n        }\n    }\n    return err\n}","preventionTips":["Probe readability with `cat <file> >/dev/null` before attaching root-owned or system files.","Avoid attaching fifos, device nodes, or files on unstable mounts.","In scripts, re-verify existence just before the call to avoid Stat/ReadFile races."],"tags":["filesystem","permissions","io","wsh"],"backgroundTag":"file-read-permission-denied","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}