valyala/fasthttp · error

cannot create temporary file for %q: %w

Error message

cannot create temporary file for %q: %w

What it means

fasthttp compresses files into cache files written via os.CreateTemp in the directory of the target compressed file. If CreateTemp fails and the error is not fs.ErrPermission, this error wraps the cause. ErrPermission is deliberately mapped to the sentinel errNoCreatePermission instead, so this error signals other temp-creation failures (missing directory, ENOSPC, name issues).

Source

Thrown at fs.go:1747

	// It is safe opening such a file, since the file creation
	// is guarded by file mutex - see getFileLock call.
	if _, err := os.Stat(compressedFilePath); err == nil {
		_ = f.Close()
		return h.newCompressedFSFile(compressedFilePath, fileEncoding)
	}

	// Create temporary file, so concurrent goroutines don't use
	// it until it is created.
	//
	// os.CreateTemp gives the file a random name and opens it with O_EXCL and
	// 0600, so a symlink pre-planted at the otherwise predictable temp path
	// can't be followed to truncate an arbitrary file, and the cache file
	// isn't left group/world-readable.
	zf, err := os.CreateTemp(filepath.Dir(compressedFilePath), filepath.Base(compressedFilePath)+".tmp-*")
	if err != nil {
		_ = f.Close()
		if !errors.Is(err, fs.ErrPermission) {
			return nil, fmt.Errorf("cannot create temporary file for %q: %w", compressedFilePath, err)
		}
		return nil, errNoCreatePermission
	}
	tmpFilePath := zf.Name()
	switch fileEncoding {
	case "br":
		zw := acquireStacklessBrotliWriter(zf, CompressDefaultCompression)
		_, err = copyZeroAlloc(zw, f)
		if errf := zw.Flush(); err == nil {
			err = errf
		}
		releaseStacklessBrotliWriter(zw, CompressDefaultCompression)
	case "gzip":
		zw := acquireStacklessGzipWriter(zf, CompressDefaultCompression)
		_, err = copyZeroAlloc(zw, f)
		if errf := zw.Flush(); err == nil {
			err = errf
		}

View on GitHub (pinned to c96f600972)

Solutions

  1. Make the directory containing the target compressed file writable by the server process (chown/chmod, or write to a user-owned dir).
  2. Pre-create the cache directory (FS.CachePath / Compress dirs) before starting the server.
  3. Free disk space if the cause is ENOSPC.
  4. If you see 'permission denied' style errors surfaced as errNoCreatePermission instead, disable compression or point compression output to a writable location.
  5. Run the server in a writable filesystem (not read-only mount).

Example fix

// before
fs := &fasthttp.FS{Root: "/var/www", Compress: true} // dir not writable
// after
_ = os.MkdirAll("/var/www", 0o755)
// and ensure the service user can write:
// sudo chown appuser /var/www
fs := &fasthttp.FS{Root: "/var/www", Compress: true}
Defensive patterns

Strategy: validation

Validate before calling

cacheDir := filepath.Dir(targetCompressedPath)
if fi, err := os.Stat(cacheDir); err != nil || !fi.IsDir() {
    os.MkdirAll(cacheDir, 0o755)
}
if err := unix.Access(cacheDir, unix.W_OK); err != nil {
    // chown/chmod before enabling compression
}

Try / catch

if strings.Contains(err.Error(), "cannot create temporary file") {
    ctx.Error("cache storage failure", fasthttp.StatusInternalServerError)
}

Prevention

When it happens

Trigger: Enabling FS.Compress / CompressBrotli / ServeFile with compression where the cache directory does not exist, is not writable, or the filesystem is full; the compressed file's directory differs from the source dir and lacks write permission for reasons other than plain ErrPermission (e.g. read-only mount).

Common situations: Running the server as non-root but pointing FS at a root-owned directory; read-only container filesystems; disk full on the partition holding static files; tmpcleaners deleting the cache directory mid-run.

Related errors


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