valyala/fasthttp · error

cannot read header of the file %q: %w

Error message

cannot read header of the file %q: %w

What it means

When building the *fsFile for a (possibly compressed) file, fasthttp needs a Content-Type. If mime.TypeByExtension can't determine it from the extension, it reads the first bytes of the file (readFileHeader, decompressing if needed) to sniff the type via http.DetectContentType. If that header read fails, this error wraps the cause with the file's base name. The file cannot be served without a content type path succeeding.

Source

Thrown at fs.go:1842

	if err != nil {
		return nil, fmt.Errorf("error when compressing file %q: %w", filePath, err)
	}

	seeker, ok := f.(io.Seeker)
	if !ok {
		return nil, errors.New("seek is not implemented")
	}
	if _, err = seeker.Seek(0, io.SeekStart); err != nil {
		return nil, err
	}

	ext := fileExtension(fileInfo.Name(), false, h.compressedFileSuffixes[fileEncoding])
	contentType := mime.TypeByExtension(ext)
	if contentType == "" {
		data, err := readFileHeader(f, false, fileEncoding)
		if err != nil {
			return nil, fmt.Errorf("cannot read header of the file %q: %w", fileInfo.Name(), err)
		}
		contentType = http.DetectContentType(data)
	}

	dirIndex := w.B
	lastModified := fileInfo.ModTime()
	ff := &fsFile{
		h:               h,
		dirIndex:        dirIndex,
		contentType:     contentType,
		contentLength:   len(dirIndex),
		compressed:      true,
		lastModified:    lastModified,
		lastModifiedStr: AppendHTTPDate(nil, lastModified),

		t: time.Now(),
	}

View on GitHub (pinned to c96f600972)

Solutions

  1. Check the wrapped cause; if reading the compressed cache failed, delete the stale compressed cache files (suffix .fasthttp.*) and let them regenerate.
  2. Ensure served files are fully written (atomic uploads: write temp + rename).
  3. Add the file's extension mapping via mime.AddExtensionType so sniffing isn't needed.
  4. Verify the file is non-empty and readable by the server user.

Example fix

// before: extensionless, truncated file causes sniff failure
// after: register MIME and ensure atomic writes
mime.AddExtensionType("", "application/octet-stream")
// upload pattern:
// os.WriteFile(f+".tmp", data, 0o644); os.Rename(f+".tmp", f)
Defensive patterns

Strategy: validation

Validate before calling

mime.AddExtensionType("", "application/octet-stream")
if fi, err := os.Stat(path); err != nil || fi.Size() == 0 {
    // reject empty/missing files before serving
}

Try / catch

if strings.Contains(err.Error(), "cannot read header of the file") {
    // delete stale *.fasthttp.* cache and serve 500/404; files will regenerate
}

Prevention

When it happens

Trigger: Requesting a file whose extension is unknown to mime.TypeByExtension AND whose content cannot be read/decompressed for sniffing — e.g. corrupted compressed cache file, read error mid-header, or a file that shrank to 0 bytes after Stat.

Common situations: Serving files without extensions that were truncated or corrupted; a stale/corrupt fasthttp compressed cache file (e.g. .fasthttp.gz) truncated by a crash; deploying partially uploaded files.

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/c22524bfe6bebffb. Report an issue: GitHub.