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
- Verify write access and free space on the plugins filesystem: df -h <PluginsDir> and touch <PluginsDir>/.probe
- Check the fd limit of the running process (/proc/<pid>/limits) and raise ulimit -n or fix the fd leak
- 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
- Monitor open-fd counts on long-running hosts (/proc/<pid>/fd)
- Keep free inodes and space on the plugins volume above a floor
- Verify the plugins mount stayed read-write after any storage remount event
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
- create plugin directory: %w
- write temp plugin file: %w
- plugin_update_requires_restart
- stat target plugin: %w
- zip contains multiple target dynamic libraries
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/01c1831b843397f4.
Report an issue: GitHub.