{"record":{"id":"1d02f499f77bc5c4","repo":"chenhg5/cc-connect","slug":"read-attachment-s-w","errorCode":null,"errorMessage":"read attachment %s: %w","messagePattern":"read attachment (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cc-connect/send.go","lineNumber":305,"sourceCode":"// or invalid config never breaks sending; the caller then falls back to the\n// env var / default via resolveMaxAttachmentSize.\nfunc loadSendConfigBestEffort() *config.Config {\n\tcfg, err := config.Load(resolveConfigPath(\"\"))\n\tif err != nil {\n\t\treturn nil\n\t}\n\treturn cfg\n}\n\n// readAttachment reads a single attachment file, rejecting anything larger than\n// maxSize bytes (resolved by the caller from config/env/default). The limit is\n// enforced before the file is read into memory.\nfunc readAttachment(path string, maxSize int64) ([]byte, string, string, error) {\n\tcleaned := filepath.Clean(path)\n\n\tinfo, err := os.Stat(cleaned)\n\tif err != nil {\n\t\treturn nil, \"\", \"\", fmt.Errorf(\"read attachment %s: %w\", path, err)\n\t}\n\tif info.Size() > maxSize {\n\t\treturn nil, \"\", \"\", fmt.Errorf(\"attachment %s exceeds size limit (%d MB)\", path, maxSize>>20)\n\t}\n\n\tdata, err := os.ReadFile(cleaned)\n\tif err != nil {\n\t\treturn nil, \"\", \"\", fmt.Errorf(\"read attachment %s: %w\", path, err)\n\t}\n\tfileName := filepath.Base(cleaned)\n\treturn data, fileName, detectAttachmentMimeType(fileName, data), nil\n}\n\nfunc detectAttachmentMimeType(fileName string, data []byte) string {\n\text := strings.ToLower(filepath.Ext(fileName))\n\tswitch ext {\n\tcase \".md\", \".markdown\":\n\t\treturn \"text/markdown; charset=utf-8\"","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/cmd/cc-connect/send.go#L287-L323","documentation":"readAttachment wraps any os.Stat failure on an attachment path with `read attachment %s: %w`. The path is cleaned with filepath.Clean before stat; if stat fails the original path is echoed back with the underlying error (typically a fs.ErrNotExist). This is the first gate before the size check and reading the file into memory.","triggerScenarios":"Calling loadImageAttachments/loadFileAttachments/loadTypedFileAttachments (via `cc-connect send`) with a path that does not exist or cannot be stat'ed — e.g. a typo'd path, a dangling symlink, or an unreadable parent directory.","commonSituations":"Typos in attachment paths, running from a different working directory than assumed, shell glob that expanded to nothing and was passed literally, deleted temp files.","solutions":["Verify the path exists: run `ls -l <path>` exactly as passed to the send command","Check the working directory — relative paths resolve against it","If the path is produced by a glob, ensure the glob matches at least one file before invoking the command"],"exampleFix":"// before\ncc-connect send ./attacments/report.pdf\n// after\ncc-connect send ./attachments/report.pdf","handlingStrategy":"validation","validationCode":"path=\"./attachments/report.pdf\"; [ -e \"$path\" ] || { echo \"missing: $path\" >&2; exit 1; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Tab-complete paths to avoid typos","Use absolute paths in scripts","Check glob expansion matches non-empty before invoking the command"],"tags":["cli","attachments","file-not-found","filesystem"],"backgroundTag":"file-not-found","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}