{"record":{"id":"c6b7a126cc034b11","repo":"router-for-me/CLIProxyAPI","slug":"sync-temp-plugin-file-w","errorCode":null,"errorMessage":"sync temp plugin file: %w","messagePattern":"sync temp plugin file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginstore/install.go","lineNumber":552,"sourceCode":"\t\t\tif errClose := temp.Close(); errClose != nil {\n\t\t\t\tlog.WithError(errClose).Debug(\"failed to close temp plugin file\")\n\t\t\t}\n\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)","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/install.go#L534-L570","documentation":"Wrapped error from temp.Sync in writeFileAtomic (install.go:551-553). The staged temp file is fsync'ed before rename so the library is durable on disk before it becomes visible. Sync failing usually means storage-level trouble — EIO, or sync unsupported/disallowed by the mount.","triggerScenarios":"InstallArchive with PluginsDir on a filesystem where fsync returns an error (some network mounts, vfat under certain conditions, FUSE filesystems with sync disabled, or real device errors).","commonSituations":"Plugins dir on a FUSE/network mount (sshfs, some CIFS configs) that rejects fsync; failing hardware; VMs with misconfigured virtio storage.","solutions":["Move PluginsDir to a local filesystem that supports fsync and retry","If on network storage, adjust mount options (e.g. CIFS 'sync' semantics) per your platform docs","Investigate repeated EIO — it frequently precedes disk failure"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"func fsyncSupported(dir string) error {\n    p := filepath.Join(dir, \".sync-probe\")\n    f, err := os.Create(p)\n    if err != nil { return err }\n    defer os.Remove(p)\n    defer f.Close()\n    return f.Sync()\n}","typeGuard":null,"tryCatchPattern":"if _, err := store.InstallArchive(data, plugin, opts); err != nil {\n    if strings.Contains(err.Error(), \"sync temp plugin file\") {\n        // mount-level fsync failure: relocate PluginsDir to local disk and retry\n    }\n}","preventionTips":["Do not host the plugins directory on FUSE/sshfs-style mounts","For network mounts, configure them with fsync semantics your platform supports","Take repeated sync EIO errors seriously — they often precede hardware failure"],"tags":["pluginstore","filesystem","durability","io"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}