valyala/fasthttp · error

cannot obtain info for original file %q: %w

Error message

cannot obtain info for original file %q: %w

What it means

When serving with compression enabled, fasthttp stats the original (uncompressed) file after opening the possibly-compressed one, to compare modification times and decide whether to regenerate the gzip file. This error wraps a failure of that Stat call on filePathOriginal.

Source

Thrown at fs.go:1915

	if err != nil {
		_ = f.Close()
		return nil, fmt.Errorf("cannot obtain info for file %q: %w", filePath, err)
	}

	if fileInfo.IsDir() {
		_ = f.Close()
		if mustCompress {
			return nil, fmt.Errorf("directory with unexpected suffix found: %q: suffix: %q",
				filePath, h.compressedFileSuffixes[fileEncoding])
		}
		return nil, errDirIndexRequired
	}

	if mustCompress {
		fileInfoOriginal, err := fs.Stat(h.filesystem, filePathOriginal)
		if err != nil {
			_ = f.Close()
			return nil, fmt.Errorf("cannot obtain info for original file %q: %w", filePathOriginal, err)
		}

		// Only re-create the compressed file if there was more than a second between the mod times.
		// On macOS the gzip seems to truncate the nanoseconds in the mod time causing the original file
		// to look newer than the gzipped file.
		if fileInfoOriginal.ModTime().Sub(fileInfo.ModTime()) >= time.Second {
			// The compressed file became stale. Re-create it.
			_ = f.Close()
			_ = os.Remove(filePath)
			return h.compressAndOpenFSFile(filePathOriginal, fileEncoding)
		}
	}

	return h.newFSFile(f, fileInfo, mustCompress, filePath, fileEncoding)
}

func (h *fsHandler) newFSFile(f fs.File, fileInfo fs.FileInfo, compressed bool, filePath, fileEncoding string) (*fsFile, error) {
	n := fileInfo.Size()

View on GitHub (pinned to c96f600972)

Solutions

  1. Keep the original uncompressed file alongside the .gz/.br file
  2. Verify the original file path exists and is accessible
  3. Fix symlinks or deploy scripts that remove originals
  4. Disable Compress in the FS config if only pre-compressed files are deployed

Example fix

// before
$ rm dist/app.js      # keep only dist/app.js.gz
// after
$ gzip -k dist/app.js # keep both dist/app.js and dist/app.js.gz
Defensive patterns

Strategy: validation

Validate before calling

for _, p := range []string{orig, orig + ".gz"} { if _, err := os.Stat(p); err != nil { return err } }

Try / catch

if err := ctx.SendFile(path); err != nil { log.Printf("compress-served file error: %v", err); ctx.Error("internal", 500) }

Prevention

When it happens

Trigger: Using an FS handler with Compress enabled where the original file (path without the compressed suffix) cannot be stat'd: it was deleted, renamed, or the path is invalid on the custom filesystem.

Common situations: Pre-compressed workflow where the .gz file is kept but the original was removed; symlinks pointing to non-existent originals; race during asset redeployment.

Related errors


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