flipped-aurora/gin-vue-admin · error

function file.Open() failed, err:

Error message

function file.Open() failed, err:

What it means

CloudflareR2.UploadFile calls file.Open() on the incoming multipart file handle before uploading to R2 via the S3-compatible uploader. If opening the multipart file part fails (e.g. the multipart section was already consumed or the request was malformed), this error wraps openError and aborts the upload.

Source

Thrown at server/utils/upload/cloudflare_r2.go:36

	"github.com/flipped-aurora/gin-vue-admin/server/global"
	"github.com/flipped-aurora/gin-vue-admin/server/utils/logger"
)

type CloudflareR2 struct{}

func (c *CloudflareR2) UploadFile(ctx context.Context, file *multipart.FileHeader) (fileUrl string, fileName string, err error) {
	client, err := c.newR2Client()
	if err != nil {
		return "", "", err
	}
	uploader := manager.NewUploader(client)

	fileKey := fmt.Sprintf("%d_%s", time.Now().Unix(), file.Filename)
	fileName = fmt.Sprintf("%s/%s", global.GVA_CONFIG.CloudflareR2.Path, fileKey)
	f, openError := file.Open()
	if openError != nil {
		logger.WithCtx(ctx).Mod("upload").Err(openError).Error("function file.Open() failed")
		return "", "", errors.New("function file.Open() failed, err:" + openError.Error())
	}
	defer f.Close() // 创建文件 defer 关闭

	_, err = uploader.Upload(context.TODO(), &s3.PutObjectInput{
		Bucket: aws.String(global.GVA_CONFIG.CloudflareR2.Bucket),
		Key:    aws.String(fileName),
		Body:   f,
	})
	if err != nil {
		logger.WithCtx(ctx).Mod("upload").Err(err).Error("function uploader.Upload() failed")
		return "", "", err
	}

	return fmt.Sprintf("%s/%s", global.GVA_CONFIG.CloudflareR2.BaseURL, fileName), fileKey, nil
}

func (c *CloudflareR2) DeleteFile(ctx context.Context, key string) error {
	client, err := c.newR2Client()

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Open the file (file.Open()) immediately after receiving the header, before other middleware or I/O touches the request body
  2. Verify the HTTP client sends multipart/form-data with a proper Content-Length (avoid streaming without length through proxies that truncate)
  3. Increase request/response timeouts if large uploads exceed server limits
  4. Ensure the FileHeader is used only once and within the request's lifetime
  5. Log the request size and Content-Type to confirm the multipart form was fully received

Example fix

// before
fh := c.Request.MultipartForm.File["file"][0]
go uploadLater(fh) // request body closed by then -> Open() fails
// after
f, err := fh.Open()
if err != nil { ... }
defer f.Close()
go uploadLater(f)
Defensive patterns

Strategy: try-catch

Validate before calling

fh, err := c.FormFile("file")
if err != nil {
    return c.JSON(400, gin.H{"msg": "multipart form missing or truncated"})
}
if fh.Size == 0 {
    return c.JSON(400, gin.H{"msg": "empty file"})
}

Type guard

null

Try / catch

url, name, err := uploader.UploadFile(ctx, fileHeader, fileName)
if err != nil {
    if strings.Contains(err.Error(), "file.Open() failed") {
        return c.JSON(400, gin.H{"msg": "upload payload invalid or truncated"})
    }
    return c.JSON(500, gin.H{"msg": "upload failed"})
}

Prevention

When it happens

Trigger: UploadFile(ctx, file, ...) where the *multipart.FileHeader cannot be opened: the underlying multipart form data was truncated, the file header was reused after the request body was closed, or the client sent a corrupt multipart payload.

Common situations: Uploading zero-byte/aborted requests, middleware already consumed the request body, request timeout closing the body before Open, proxies buffering truncation, reusing a FileHeader across goroutines after the request finished.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/dfbf7122627ec96b. Report an issue: GitHub.