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

  1. Free space on the plugins volume (df -h) and retry the install
  2. Raise the user's disk quota if quotas are in effect
  3. 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

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


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