gofiber/fiber · error · ErrFileOpen

%w: %q: %w

Error message

%w: %q: %w

What it means

Returned by Ctx.SaveFileToStorage when multipart.FileHeader.Open() fails while accessing the uploaded file's content. The error wraps the sentinel ErrFileOpen ('file: failed to open file'), the original filename, and the underlying OS/multipart error: 'file: failed to open file: "report.pdf": <err>'. This is an early failure in the save-to-storage pipeline, before size limiting or reading begins.

Source

Thrown at ctx.go:572

}

// SaveFile saves any multipart file to disk.
func (*DefaultCtx) SaveFile(fileheader *multipart.FileHeader, path string) error {
	if fileheader == nil {
		return ErrFileHeaderNil
	}
	return fasthttp.SaveMultipartFile(fileheader, path)
}

// SaveFileToStorage saves any multipart file to an external storage system.
func (c *DefaultCtx) SaveFileToStorage(fileheader *multipart.FileHeader, path string, storage Storage) error {
	if fileheader == nil {
		return ErrFileHeaderNil
	}

	file, err := fileheader.Open()
	if err != nil {
		return fmt.Errorf("%w: %q: %w", ErrFileOpen, fileheader.Filename, err)
	}
	defer file.Close() //nolint:errcheck // not needed

	maxUploadSize := c.app.config.BodyLimit
	if maxUploadSize <= 0 {
		maxUploadSize = DefaultBodyLimit
	}

	if fileheader.Size > 0 && fileheader.Size > int64(maxUploadSize) {
		return fmt.Errorf("%w: %q: %w", ErrFileRead, fileheader.Filename, fasthttp.ErrBodyTooLarge)
	}

	buf := bytebufferpool.Get()
	defer bytebufferpool.Put(buf)

	limitedReader := io.LimitReader(file, int64(maxUploadSize)+1)
	if _, err = buf.ReadFrom(limitedReader); err != nil {
		return fmt.Errorf("%w: %q: %w", ErrFileRead, fileheader.Filename, err)

View on GitHub (pinned to a105acad6c)

Solutions

  1. Do not read or save the same multipart file twice; consume it once in a single handler.
  2. Inspect the wrapped underlying error (errors.Unwrap / errors.Is(err, ErrFileOpen)) to identify the OS cause.
  3. If reproducing in tests, build the FileHeader from real multipart data via a httptest request rather than a hand-constructed struct.
  4. Handle the error with a 4xx/5xx response appropriate to the cause (client gone vs. server I/O).

Example fix

if err := c.SaveFileToStorage(fh, key, store); err != nil {
    if errors.Is(err, fiber.ErrFileOpen) {
        return c.Status(fiber.StatusBadGateway).SendString("could not open upload")
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

if err := c.SaveFileToStorage(fh, key, store); err != nil {
    if errors.Is(err, fiber.ErrFileOpen) {
        // underlying multipart part could not be opened
        return fiber.NewError(fiber.StatusBadRequest, "upload unavailable")
    }
    return err
}

Prevention

When it happens

Trigger: Calling c.SaveFileToStorage(fileheader, path, storage) where the multipart header is present but its underlying part cannot be opened. The fileheader must be non-nil (a nil header returns ErrFileHeaderNil earlier).

Common situations: The upload was already consumed/drained by an earlier handler, the temp file backing the multipart part was deleted under the process, or the OS returned an I/O error opening the spilled part. Rare in normal operation; more likely in tests that hand-craft FileHeader values.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/724a831aaa6bc096. Report an issue: GitHub.