{"record":{"id":"cca783db8945b392","repo":"larksuite/cli","slug":"attachment-q-w","errorCode":null,"errorMessage":"attachment %q: %w","messagePattern":"attachment %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/mail/emlbuilder/builder.go","lineNumber":66,"sourceCode":"\t\"math/rand\"\n\t\"mime\"\n\t\"net/mail\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/larksuite/cli/extension/fileio\"\n\t\"github.com/larksuite/cli/internal/validate\"\n\t\"github.com/larksuite/cli/shortcuts/mail/filecheck\"\n)\n\n// MaxEMLSize is the maximum allowed raw EML size in bytes.\nconst MaxEMLSize = 25 * 1024 * 1024 // 25 MB\n\n// readFile reads the named file and returns its contents via FileIO.\nfunc readFile(fio fileio.FileIO, path string) ([]byte, error) {\n\tif _, err := validate.SafeInputPath(path); err != nil {\n\t\treturn nil, fmt.Errorf(\"attachment %q: %w\", path, err) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.\n\t}\n\tf, err := fio.Open(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"attachment %q: %w\", path, err) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.\n\t}\n\tdefer f.Close()\n\treturn io.ReadAll(f)\n}\n\n// Builder constructs a Lark-compatible RFC 2822 EML message.\n// All setter methods return a copy of the Builder (immutable/fluent style),\n// so a base builder can be reused across multiple goroutines safely.\ntype Builder struct {\n\tfio                       fileio.FileIO // injected via WithFileIO; must be set before AddFile* calls\n\tfrom                      mail.Address\n\tto                        []mail.Address\n\tcc                        []mail.Address\n\tbcc                       []mail.Address","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/mail/emlbuilder/builder.go#L48-L84","documentation":"readFile in the EML builder validates each attachment path with validate.SafeInputPath before opening it. If path validation fails (path outside allowed roots, invalid/unresolvable path, safety rejection), the error is wrapped as `attachment \"<path>\": <cause>`. This is an intermediate untyped error that the mail command layer later converts into a typed ValidationError, which is why the raw fmt.Errorf is nolint-waived.","triggerScenarios":"Calling AddFileAttachment, AddFileInline, or AddFileOtherPart with a path that validate.SafeInputPath rejects: relative path with no valid base, traversal outside allowed roots, nonexistent parent resolution, or otherwise unsafe input path.","commonSituations":"Attaching files from a temp directory that was cleaned up; passing user-supplied relative paths; running under the FileIO-scoped/portable boundary where only validated workspace paths are accepted; typos or stale paths in scripts.","solutions":["Verify the attachment path exists and is inside the allowed root","Use an absolute, validated path (or one resolved via runtime.ValidatePath/ResolveSavePath) before AddFileAttachment","Check the wrapped cause in the error to see which path rule rejected it","Copy the file into the allowed workspace tree if it lives outside"],"exampleFix":"// before\nb.AddFileAttachment(fio, \"../secrets/notes.pdf\")\n// after\nb.AddFileAttachment(fio, \"/workspace/attachments/notes.pdf\") // absolute, allowed root","handlingStrategy":"validation","validationCode":"for _, p := range attachmentPaths {\n  if _, err := validate.SafeInputPath(p); err != nil {\n    return fmt.Errorf(\"skipping attachment %q: %w\", p, err)\n  }\n}","typeGuard":null,"tryCatchPattern":"err := builder.AddFileAttachment(fio, path)\nif err != nil {\n  var verr *ValidationError\n  if errors.As(err, &verr) { return userFacingPathError(path, verr) }\n  return err\n}","preventionTips":["Pass absolute paths inside the allowed root","Pre-resolve user-supplied paths via runtime.ValidatePath","Confirm attachment files exist before building the EML","Avoid relative paths that depend on process working directory"],"tags":["mail","eml-builder","path-validation","attachment"],"backgroundTag":"invalid-file-path","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}