flipped-aurora/gin-vue-admin · error

function file.Open() failed, err:

Error message

function file.Open() failed, err:

What it means

local.UploadFile opens the multipart file handle with file.Open() before saving it to disk; an error there is wrapped in this message. It indicates the *multipart.FileHeader could not yield a readable file — usually because the multipart body is gone or malformed by the time Open is called.

Source

Thrown at server/utils/upload/local.go:54

	// 读取文件名并加密
	name := strings.TrimSuffix(file.Filename, ext)
	name = utils.MD5V([]byte(name))
	// 拼接新文件名
	filename := name + "_" + time.Now().Format("20060102150405") + ext
	// 尝试创建此路径
	mkdirErr := os.MkdirAll(global.GVA_CONFIG.Local.StorePath, os.ModePerm)
	if mkdirErr != nil {
		logger.WithCtx(ctx).Mod("upload").Err(mkdirErr).Error("function os.MkdirAll() failed")
		return "", "", errors.New("function os.MkdirAll() failed, err:" + mkdirErr.Error())
	}
	// 拼接路径和文件名
	p := global.GVA_CONFIG.Local.StorePath + "/" + filename
	filepath := global.GVA_CONFIG.Local.Path + "/" + filename

	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 关闭

	out, createErr := os.Create(p)
	if createErr != nil {
		logger.WithCtx(ctx).Mod("upload").Err(createErr).Error("function os.Create() failed")

		return "", "", errors.New("function os.Create() failed, err:" + createErr.Error())
	}
	defer out.Close() // 创建文件 defer 关闭

	_, copyErr := io.Copy(out, f) // 传输(拷贝)文件
	if copyErr != nil {
		logger.WithCtx(ctx).Mod("upload").Err(copyErr).Error("function io.Copy() failed")
		return "", "", errors.New("function io.Copy() failed, err:" + copyErr.Error())
	}
	return filepath, filename, nil
}

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Open the file right in the handler before spawning goroutines or doing other body-consuming work
  2. Raise proxy/client_max_body_size and Go's multipart limits to fit your max upload size
  3. Return 400 early when Content-Length indicates truncation instead of attempting to open
  4. Don't retain *multipart.FileHeader beyond the request lifetime; copy to a temp file if async processing is needed
  5. Verify with curl -F that a small file uploads correctly to isolate size-related truncation

Example fix

// before
func handler(c *gin.Context) {
    fh, _ := c.FormFile("file")
    go func() { uploader.UploadFile(ctx, fh, name) }() // Open() fails: body closed
}
// after
func handler(c *gin.Context) {
    fh, _ := c.FormFile("file")
    f, _ := fh.Open()
    defer f.Close()
    go func() { save(f) }()
}
Defensive patterns

Strategy: try-catch

Validate before calling

fh, err := c.FormFile("file")
if err != nil {
    return c.JSON(400, gin.H{"msg": "no valid file in request"})
}
if fh.Size == 0 {
    return c.JSON(400, gin.H{"msg": "empty upload rejected"})
}

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 was truncated or already consumed"})
    }
    if strings.Contains(err.Error(), "os.Create() failed") {
        return c.JSON(500, gin.H{"msg": "server storage write failed"})
    }
    return err
}

Prevention

When it happens

Trigger: UploadFile(ctx, file, ...) where the FileHeader cannot be opened: request body already consumed/closed, truncated multipart payload, zero-byte aborted upload, or the header used after the HTTP request completed.

Common situations: Client aborts mid-upload, reverse proxy truncates large bodies, middleware (e.g. body-dumping logger) consumed the form, goroutine processing the FileHeader after the handler returned, server upload limits (MaxMultipartMemory / proxy client_max_body_size) cutting the payload.

Related errors


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