router-for-me/CLIProxyAPI · error
write temp plugin file: %w
Error message
write temp plugin file: %w
What it means
Wrapped error from temp.Write in writeFileAtomic (install.go:548-550). After staging and chmod'ing the temp file, the library bytes are written; failure here is a classic storage failure — ENOSPC (disk full), EIO, or quota exceeded on the plugins directory.
Source
Thrown at internal/pluginstore/install.go:549
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 {
return fmt.Errorf("chmod temp plugin file: %w", errChmod)
}
if _, errWrite := temp.Write(data); errWrite != nil {
return fmt.Errorf("write temp plugin file: %w", errWrite)
}
if errSync := temp.Sync(); errSync != nil {
return fmt.Errorf("sync temp plugin file: %w", errSync)
}
if errClose := temp.Close(); errClose != nil {
return fmt.Errorf("close temp plugin file: %w", errClose)
}
closed = true
if errRename := os.Rename(tempPath, targetPath); errRename != nil {
if runtime.GOOS == "windows" {
if errRemove := os.Remove(targetPath); errRemove != nil && !errors.Is(errRemove, os.ErrNotExist) {
return fmt.Errorf("remove old plugin file: %w", errRemove)
}
if errRenameRetry := os.Rename(tempPath, targetPath); errRenameRetry == nil {
removeTemp = false
return nil
} else {
return fmt.Errorf("install plugin file: %w", errRenameRetry)View on GitHub (pinned to 78f0c4079e)
Solutions
- Free space on the plugins volume (df -h) and retry the install
- Raise the user's disk quota if quotas are in effect
- Relocate PluginsDir to a volume with adequate free space for the plugin plus headroom
Defensive patterns
Strategy: retry
Validate before calling
func hasFreeSpace(dir string, needBytes uint64) bool {
var st syscall.Statfs_t
if err := syscall.Statfs(dir, &st); err != nil { return false }
return st.Bavail*uint64(st.Bsize) > needBytes
} Try / catch
if _, err := store.InstallArchive(data, plugin, opts); err != nil {
if errors.Is(err, syscall.ENOSPC) {
// free space, then retry — installArchive is idempotent
}
} Prevention
- Alert on disk usage of the plugins volume before it fills
- Size container volumes for the largest plugin artifact plus headroom
- Clean superseded plugin versions periodically
When it happens
Trigger: InstallArchive when the volume holding PluginsDir runs out of space mid-write (large plugin libraries), a disk quota is hit, or the underlying device returns an I/O error. The deferred cleanup at install.go:534-544 removes the partial temp file, so no half-written library is left behind.
Common situations: Full disk in containers with small overlay2 roots; per-user quotas on shared hosts; failing disks returning EIO.
Related errors
- create plugin directory: %w
- create temp plugin file: %w
- plugin_update_requires_restart
- failed to write token to file: %w
- failed to write token to file: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/d2114ecb072258b1.
Report an issue: GitHub.