vxcontrol/pentagi · error

failed to create temp file

Error message

failed to create temp file: %w

What it means

SaveToTemp creates the temporary file with os.CreateTemp(dir, ".resource-upload-*"); this error wraps CreateTemp's failure. Even when the directory exists, file creation can fail due to permissions, exhausted inodes, or filesystem errors.

Solutions

  1. Check write permission on dir for the running user and the mount flags (mount | grep <dir>)
  2. Check open file descriptor limits (ulimit -n) and raise them if uploads fail under load
  3. Verify the volume is mounted rw and no security module is denying creation (dmesg/audit logs)
  4. Ensure dir still exists at call time — don't delete it concurrently

Example fix

// before
ulimit -n 1024  # too low for concurrent uploads
// after
ulimit -n 65536  # or set LimitNOFILE=65536 in the systemd unit
Defensive patterns

Strategy: retry

Validate before calling

func canCreateTemp(dir string) error {
	f, err := os.CreateTemp(dir, ".probe-*")
	if err != nil {
		return err
	}
	name := f.Name()
	f.Close()
	return os.Remove(name)
}

Try / catch

var tmpPath, hash string
var size int64
err := retry.Do(func() error {
	tp, h, s, e := resources.SaveToTemp(r, dir)
	if e != nil {
		var perr *fs.PathError
		if errors.As(e, &perr) && errors.Is(perr.Err, syscall.ENOSPC) {
			return retry.Unrecoverable(e) // don't retry disk-full
		}
		return e
	}
	tmpPath, hash, size = tp, h, s
	return nil
}, retry.Attempts(3))

Prevention

When it happens

Trigger: dir exists but is not writable by the process user; the filesystem ran out of inodes; security policies (e.g. read-only tmpfs, AppArmor/SELinux) block creation; too many open file descriptors. Raised via UploadResources or direct calls.

Common situations: ulimit -n exhaustion under heavy upload load; Kubernetes securityContext with readOnlyRootFilesystem; SELinux denials on container volumes; tmp-cleaner scripts removing the directory between MkdirAll and CreateTemp.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/f08a7eef3fdfafe2. Report an issue: GitHub.

Appendix: source

Thrown at backend/pkg/resources/resources.go:280

// EscapeLike escapes special LIKE pattern characters (%, _) in s so the string
// can be safely embedded in a SQL LIKE clause.
func EscapeLike(s string) string {
	s = strings.ReplaceAll(s, `\`, `\\`)
	s = strings.ReplaceAll(s, `%`, `\%`)
	s = strings.ReplaceAll(s, `_`, `\_`)
	return s
}

// SaveToTemp writes r into a new temporary file in dir and returns the path to
// the temp file. The caller is responsible for removing the temp file on error.
func SaveToTemp(r io.Reader, dir string) (tmpPath string, hash string, size int64, err error) {
	if err := os.MkdirAll(dir, 0755); err != nil {
		return "", "", 0, fmt.Errorf("failed to create temp directory: %w", err)
	}

	tmp, err := os.CreateTemp(dir, ".resource-upload-*")
	if err != nil {
		return "", "", 0, fmt.Errorf("failed to create temp file: %w", err)
	}
	tmpPath = tmp.Name()
	defer tmp.Close()

	h := md5.New()
	mw := io.MultiWriter(tmp, h)
	written, copyErr := io.Copy(mw, r)
	if copyErr != nil {
		os.Remove(tmpPath)
		return "", "", 0, fmt.Errorf("failed to write temp file: %w", copyErr)
	}
	if err := tmp.Chmod(0644); err != nil {
		os.Remove(tmpPath)
		return "", "", 0, fmt.Errorf("failed to set temp file permissions: %w", err)
	}

	return tmpPath, hex.EncodeToString(h.Sum(nil)), written, nil
}

View on GitHub (pinned to ea665308ba)