router-for-me/CLIProxyAPI · error

create temp plugin file: %w

Error message

create temp plugin file: %w

What it means

Wrapped error from os.CreateTemp inside writeFileAtomic (install.go:526-528). The atomic-write pattern stages a temp file '.'+base+'.tmp-*' in the target directory, then renames it over the final library path. CreateTemp can fail on permission errors or when the process hit its open-file descriptor limit, even though MkdirAll succeeded.

Source

Thrown at internal/pluginstore/install.go:527

	switch strings.ToLower(strings.TrimSpace(goos)) {
	case "darwin", "mac", "macos", "osx":
		return ".dylib"
	case "windows":
		return ".dll"
	default:
		return ".so"
	}
}

func writeFileAtomic(targetPath string, data []byte, mode os.FileMode) error {
	targetDir := filepath.Dir(targetPath)
	if errMkdir := os.MkdirAll(targetDir, 0o755); errMkdir != nil {
		return fmt.Errorf("create plugin directory: %w", errMkdir)
	}

	temp, errTemp := os.CreateTemp(targetDir, "."+filepath.Base(targetPath)+".tmp-*")
	if errTemp != nil {
		return fmt.Errorf("create temp plugin file: %w", errTemp)
	}
	tempPath := temp.Name()
	removeTemp := true
	closed := false
	defer func() {
		if !closed {
			if errClose := temp.Close(); errClose != nil {
				log.WithError(errClose).Debug("failed to close temp plugin file")
			}
		}
		if removeTemp {
			if errRemove := os.Remove(tempPath); errRemove != nil && !errors.Is(errRemove, os.ErrNotExist) {
				log.WithError(errRemove).Debug("failed to remove temp plugin file")
			}
		}
	}()

	if errChmod := temp.Chmod(mode); errChmod != nil {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Verify write access and free space on the plugins filesystem: df -h <PluginsDir> and touch <PluginsDir>/.probe
  2. Check the fd limit of the running process (/proc/<pid>/limits) and raise ulimit -n or fix the fd leak
  3. Remount or repoint the volume read-write and retry the install
Defensive patterns

Strategy: try-catch

Validate before calling

func canCreateFiles(pluginsDir string) error {
    tmp, err := os.CreateTemp(pluginsDir, ".probe-*")
    if err != nil { return err }
    tmp.Close()
    return os.Remove(tmp.Name())
}

Try / catch

if _, err := store.InstallArchive(data, plugin, opts); err != nil {
    if errors.Is(err, os.ErrPermission) || errors.Is(err, syscall.EMFILE) {
        // permissions or fd exhaustion: fix environment, then retry once
    }
}

Prevention

When it happens

Trigger: InstallArchive where PluginsDir was created read-only afterwards, the filesystem is full enough to refuse new inodes, or ulimit -n is exhausted (many concurrent installs, fd leak elsewhere).

Common situations: Disk full on the volume hosting the plugins dir; a long-running process leaking file descriptors; permission changes (chmod 555) applied between installs.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/01c1831b843397f4. Report an issue: GitHub.