vxcontrol/pentagi · error

'%s' is not a regular file

Error message

'%s' is not a regular file

What it means

RegularFileInfo lstats the path and requires a regular file. If the Lstat succeeds but the entry is a directory, symlink, socket, FIFO, or device, it returns "'<path>' is not a regular file". UploadFlowFiles uses this to reject non-file uploads before streaming.

Source

Thrown at backend/pkg/flowfiles/files.go:311

func LocalEntryExists(filePath string) (bool, error) {
	if _, err := os.Lstat(filePath); err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

func RegularFileInfo(filePath string) (os.FileInfo, error) {
	info, err := os.Lstat(filePath)
	if err != nil {
		return nil, err
	}
	if !info.Mode().IsRegular() {
		return nil, fmt.Errorf("'%s' is not a regular file", filePath)
	}

	return info, nil
}

func SaveUploadedFileToTemp(fh *multipart.FileHeader, dir string) (string, error) {
	src, err := fh.Open()
	if err != nil {
		return "", fmt.Errorf("failed to open uploaded file: %w", err)
	}
	defer src.Close()

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

View on GitHub (pinned to ea665308ba)

Solutions

  1. Ensure the path refers to a regular file, not a directory or symlink, before calling.
  2. If uploading a directory, enumerate its files and call the upload API per regular file.
  3. Resolve symlinks first with filepath.EvalSymlinks or os.Stat if following links is intended, then check Mode().IsRegular() yourself.

Example fix

// before
info, err := flowfiles.RegularFileInfo("/data/mydir")
// after
entries, _ := os.ReadDir("/data/mydir")
for _, e := range entries {
    if e.Type().IsRegular() {
        info, err := flowfiles.RegularFileInfo(filepath.Join("/data/mydir", e.Name()))
        // handle info/err
    }
}
Defensive patterns

Strategy: validation

Validate before calling

func ensureRegularFile(p string) error {
    info, err := os.Stat(p) // Stat follows symlinks
    if err != nil {
        return err
    }
    if !info.Mode().IsRegular() {
        return fmt.Errorf("%s is not a regular file", p)
    }
    return nil
}

Type guard

func isRegularFile(p string) bool {
    info, err := os.Stat(p)
    return err == nil && info.Mode().IsRegular()
}

Try / catch

if err != nil {
    if strings.HasSuffix(err.Error(), "is not a regular file") {
        return fmt.Errorf("skip or expand directories/symlinks before upload: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling flowfiles.RegularFileInfo on a directory path, a symlink (Lstat does not follow links), or a special file (device/socket/FIFO) — e.g. when a user selects a folder for upload, or a path that turned out to be a symlink to a file.

Common situations: Uploading a directory instead of files from the UI/CLI; dragging a symlink into an upload form; referencing /dev/null or a Unix socket; a path that existed as a file but was replaced by a symlink between listing and upload (TOCTOU).

Related errors


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