valyala/fasthttp · error
cannot move compressed file from %q to %q: %w
Error message
cannot move compressed file from %q to %q: %w
What it means
After compression and timestamp fix-up succeed, fasthttp atomically moves the temp file into its final compressed-cache location with os.Rename. If the rename fails, the temp file is removed and this error wraps the cause, naming source (temp) and destination paths. Common causes are cross-device renames or a missing/conflicting destination directory.
Source
Thrown at fs.go:1788
if errf := zw.Flush(); err == nil {
err = errf
}
releaseStacklessZstdWriter(zw, CompressZstdDefault)
}
_ = zf.Close()
_ = f.Close()
if err != nil {
_ = os.Remove(tmpFilePath)
return nil, fmt.Errorf("error when compressing file %q to %q: %w", filePath, tmpFilePath, err)
}
if err = os.Chtimes(tmpFilePath, time.Now(), fileInfo.ModTime()); err != nil {
_ = os.Remove(tmpFilePath)
return nil, fmt.Errorf("cannot change modification time to %v for tmp file %q: %v",
fileInfo.ModTime(), tmpFilePath, err)
}
if err = os.Rename(tmpFilePath, compressedFilePath); err != nil {
_ = os.Remove(tmpFilePath)
return nil, fmt.Errorf("cannot move compressed file from %q to %q: %w", tmpFilePath, compressedFilePath, err)
}
return h.newCompressedFSFile(compressedFilePath, fileEncoding)
}
// newCompressedFSFileCache use memory cache compressed files.
func (h *fsHandler) newCompressedFSFileCache(f fs.File, fileInfo fs.FileInfo, filePath, fileEncoding string) (*fsFile, error) {
var (
w = &bytebufferpool.ByteBuffer{}
err error
)
switch fileEncoding {
case "br":
zw := acquireStacklessBrotliWriter(w, CompressDefaultCompression)
_, err = copyZeroAlloc(zw, f)
if errf := zw.Flush(); err == nil {
err = errf
}View on GitHub (pinned to c96f600972)
Solutions
- Ensure the compressed-file directory exists, is writable, and lives on the same filesystem as its temp files (don't split cache across mounts).
- Check the wrapped cause: EXDEV means cross-device rename — align temp and cache locations.
- Stop external cleaners from deleting the cache directory while the server runs.
- Retry the request; the temp file is cleaned up so the next attempt starts fresh.
Example fix
// before: cache on another mount -> EXDEV
fs := &fasthttp.FS{Root: "/srv/www", Compress: true} // tmp in /srv/www, cache target on /mnt/cache
// after: keep cache alongside source files (same fs)
fs := &fasthttp.FS{Root: "/srv/www", Compress: true, CompressedFileSuffix: ".gz"} Defensive patterns
Strategy: retry
Validate before calling
if fi, err := os.Stat(filepath.Dir(compressedPath)); err != nil || !fi.IsDir() {
os.MkdirAll(filepath.Dir(compressedPath), 0o755)
}
// ensure same device: compare syscall.Stat_t.Dev of temp dir and target dir Try / catch
if strings.Contains(err.Error(), "cannot move compressed file") {
// EXDEV => reconfigure cache to same filesystem; otherwise retry
} Prevention
- Keep temp files and final cache files on the same filesystem (avoid EXDEV).
- Don't delete the cache directory while the server is running.
- Ensure the destination directory stays writable for the service user.
When it happens
Trigger: The directory of the compressed cache path was removed between CreateTemp and Rename; the temp dir and target dir reside on different filesystems (Rename cannot cross devices); another process holds the target path in a way that makes rename fail (rare on POSIX).
Common situations: CachePath pointing to a different mounted volume than the temp file location; cache dir deleted by cleanup while under load; permission loss on the destination directory mid-run.
Related errors
- cannot create temporary file for %q: %w
- error when compressing file %q to %q: %w
- cannot change modification time to %v for tmp file %q: %v
- directory with unexpected suffix found: %q: suffix: %q
- cannot obtain info for original file %q: %w
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/fb67beeccc406cc7.
Report an issue: GitHub.