{"record":{"id":"5ae3a9fe8a6336d4","repo":"router-for-me/CLIProxyAPI","slug":"close-temp-plugin-file-w","errorCode":null,"errorMessage":"close temp plugin file: %w","messagePattern":"close temp plugin file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginstore/install.go","lineNumber":555,"sourceCode":"\t\t}\n\t\tif removeTemp {\n\t\t\tif errRemove := os.Remove(tempPath); errRemove != nil && !errors.Is(errRemove, os.ErrNotExist) {\n\t\t\t\tlog.WithError(errRemove).Debug(\"failed to remove temp plugin file\")\n\t\t\t}\n\t\t}\n\t}()\n\n\tif errChmod := temp.Chmod(mode); errChmod != nil {\n\t\treturn fmt.Errorf(\"chmod temp plugin file: %w\", errChmod)\n\t}\n\tif _, errWrite := temp.Write(data); errWrite != nil {\n\t\treturn fmt.Errorf(\"write temp plugin file: %w\", errWrite)\n\t}\n\tif errSync := temp.Sync(); errSync != nil {\n\t\treturn fmt.Errorf(\"sync temp plugin file: %w\", errSync)\n\t}\n\tif errClose := temp.Close(); errClose != nil {\n\t\treturn fmt.Errorf(\"close temp plugin file: %w\", errClose)\n\t}\n\tclosed = true\n\tif errRename := os.Rename(tempPath, targetPath); errRename != nil {\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\tif errRemove := os.Remove(targetPath); errRemove != nil && !errors.Is(errRemove, os.ErrNotExist) {\n\t\t\t\treturn fmt.Errorf(\"remove old plugin file: %w\", errRemove)\n\t\t\t}\n\t\t\tif errRenameRetry := os.Rename(tempPath, targetPath); errRenameRetry == nil {\n\t\t\t\tremoveTemp = false\n\t\t\t\treturn nil\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"install plugin file: %w\", errRenameRetry)\n\t\t\t}\n\t\t}\n\t\treturn fmt.Errorf(\"install plugin file: %w\", errRename)\n\t}\n\tremoveTemp = false\n\treturn nil","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/install.go#L537-L573","documentation":"Wrapped error from temp.Close in writeFileAtomic (install.go:554-556). After chmod/write/sync succeed, the staged file is closed before the rename. Close errors are uncommon but surface deferred write-back failures on some filesystems; if it fails, the install aborts and the temp file is removed by the deferred cleanup (closed stays false).","triggerScenarios":"InstallArchive where closing the flushed temp file fails with EIO/ENOSPC on write-back (data buffered in the page cache may fail to flush at close), or on unusual FUSE filesystems.","commonSituations":"Disk that filled between write and close due to concurrent writes by other processes; flaky network-mounted storage.","solutions":["Check free space and dmesg/agent logs for I/O errors on the plugins volume","Retry the install once transient storage pressure clears (installArchive is idempotent — byte-identical libraries are skipped at install.go:279-287)","Move PluginsDir off the misbehaving mount"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := store.InstallArchive(data, plugin, opts); err != nil {\n    if strings.Contains(err.Error(), \"close temp plugin file\") {\n        // transient flush failure: verify free space, then retry install once\n    }\n}","preventionTips":["Keep headroom on the plugins volume so buffered writes can flush at close","Retry installs after storage pressure clears — identical bytes are skipped on retry","Watch kernel logs for I/O errors on the plugins device"],"tags":["pluginstore","filesystem","io"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}