{"record":{"id":"6fa46cbff228ab10","repo":"vxcontrol/pentagi","slug":"failed-to-open-uploaded-file-w","errorCode":null,"errorMessage":"failed to open uploaded file: %w","messagePattern":"failed to open uploaded file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/flowfiles/files.go","lineNumber":320,"sourceCode":"\treturn true, nil\n}\n\nfunc RegularFileInfo(filePath string) (os.FileInfo, error) {\n\tinfo, err := os.Lstat(filePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !info.Mode().IsRegular() {\n\t\treturn nil, fmt.Errorf(\"'%s' is not a regular file\", filePath)\n\t}\n\n\treturn info, nil\n}\n\nfunc SaveUploadedFileToTemp(fh *multipart.FileHeader, dir string) (string, error) {\n\tsrc, err := fh.Open()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to open uploaded file: %w\", err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.CreateTemp(dir, \".upload-*\")\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create temporary upload file: %w\", err)\n\t}\n\ttmpPath := dst.Name()\n\tdefer dst.Close()\n\n\tif _, err := io.Copy(dst, src); err != nil {\n\t\tos.Remove(tmpPath)\n\t\treturn \"\", fmt.Errorf(\"failed to write temporary upload file: %w\", err)\n\t}\n\tif err := dst.Chmod(0644); err != nil {\n\t\tos.Remove(tmpPath)\n\t\treturn \"\", fmt.Errorf(\"failed to set temporary upload file permissions: %w\", err)\n\t}","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/flowfiles/files.go#L302-L338","documentation":"SaveUploadedFileToTemp opens the multipart.FileHeader's underlying part via fh.Open(). If that fails (rare — usually a malformed multipart body or the underlying reader/pipes being broken), it returns 'failed to open uploaded file' wrapping the cause.","triggerScenarios":"Calling SaveUploadedFileToTemp with a *multipart.FileHeader whose Open() fails: a truncated or malformed multipart body, an in-memory/piped FileHeader (e.g. built manually with FileHeader{Filename: ...} without setting Content or a valid open func), or the client disconnecting mid-request so the multipart reader is closed.","commonSituations":"Manually constructed multipart.FileHeader values in tests or code (fh.Open() returns http.ErrMissingFile or ErrMissingBoundary-adjacent failures); aborted uploads where the client closed the connection before the form finished parsing; requests where c.File or FormFile ran against a corrupted body.","solutions":["Confirm the FileHeader came from a successfully parsed request (r.ParseMultipartForm / c.FormFile), not a manually constructed struct.","Check the wrapped cause (%w) for http.ErrMissingFile or reader errors and return 400 Bad Request to the client.","For tests, build the FileHeader via a real multipart writer/reader round-trip instead of setting fields directly.","Retry or reject on client disconnect — this is a client-side failure, not a server bug."],"exampleFix":"// before\nfh, _ := c.FormFile(\"file\")\npath, err := flowfiles.SaveUploadedFileToTemp(fh, dir) // panics/fails on nil or fake fh\n// after\nfh, err := c.FormFile(\"file\")\nif err != nil {\n    c.JSON(400, gin.H{\"error\": \"file part missing\"}); return\n}\npath, err := flowfiles.SaveUploadedFileToTemp(fh, dir)\nif err != nil {\n    c.JSON(400, gin.H{\"error\": err.Error()}); return\n}","handlingStrategy":"try-catch","validationCode":"if fh == nil || fh.Size == 0 && fh.Filename == \"\" {\n    return errors.New(\"no valid uploaded file part\")\n}","typeGuard":"func hasRealUpload(fh *multipart.FileHeader) bool {\n    if fh == nil || fh.Filename == \"\" {\n        return false\n    }\n    f, err := fh.Open()\n    if err != nil {\n        return false\n    }\n    f.Close()\n    return true\n}","tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"failed to open uploaded file\") {\n        if errors.Is(err, http.ErrMissingFile) {\n            return fmt.Errorf(\"client sent no file part: %w\", err)\n        }\n        return fmt.Errorf(\"upload aborted or malformed: %w\", err)\n    }\n    return err\n}","preventionTips":["Obtain FileHeaders only from a successfully parsed multipart form.","Return 400 to clients whose upload body is truncated or aborted.","In tests, construct FileHeaders via a real multipart writer, not struct literals."],"tags":["go","multipart","file-upload"],"backgroundTag":"multipart-upload-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}