{"record":{"id":"56fe0341606c64d0","repo":"matryer/xbar","slug":"set-executable-permission-on-plugin-entry-point","errorCode":null,"errorMessage":"set executable permission on plugin entry point","messagePattern":"set executable permission on plugin entry point","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/plugins/install.go","lineNumber":135,"sourceCode":"\t\t\treturn errors.Wrapf(err, \"create directory %s for plugin\", dir)\n\t\t}\n\t\twriter, err := os.Create(pluginFile)\n\t\tif err != nil {\n\t\t\treturn errors.Wrapf(err, \"create plugin file %s\", f.Path)\n\t\t}\n\t\tdefer writer.Close()\n\t\treader := strings.NewReader(f.Content)\n\t\tif _, err := io.Copy(writer, reader); err != nil {\n\t\t\treturn errors.Wrapf(err, \"write plugin file %s\", f.Path)\n\t\t}\n\t\t// If the Filename property of the current file matches the Filename\n\t\t// property of the plugin, this is the entry point, so set it to be\n\t\t// executable.\n\t\tif f.Filename != plugin.Filename {\n\t\t\tcontinue\n\t\t}\n\t\tif err := os.Chmod(pluginFile, 0755); err != nil {\n\t\t\treturn errors.Wrap(err, \"set executable permission on plugin entry point\")\n\t\t}\n\t\t// write the default variables\n\t\tplugin, err := metadata.Parse(metadata.DebugfNoop, pluginFile, f.Content)\n\t\tif err != nil {\n\t\t\tlog.Println(\"install plugin: unable to parse metadata:\", err)\n\t\t}\n\t\tif len(plugin.Vars) > 0 {\n\t\t\tdefaultVars := make(map[string]interface{})\n\t\t\tfor _, pluginVar := range plugin.Vars {\n\t\t\t\tdefaultVars[pluginVar.Name] = pluginVar.DefaultValue()\n\t\t\t}\n\t\t\terr := SaveVariableValues(i.PluginDir, pluginFile, defaultVars)\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrap(err, \"write default variables\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/matryer/xbar/blob/d624239058997c80118eaebe2e7f8331b3c765e0/pkg/plugins/install.go#L117-L153","documentation":"Returned by writePluginFiles when os.Chmod fails to set mode 0755 on the installed plugin's entry-point file. The chmod makes the entry point executable so it can be invoked later. Failure means the process lacks ownership/permission on the file or the filesystem does not support permission changes.","triggerScenarios":"Installer.Install -> writePluginFiles, after writing the file whose f.Filename equals plugin.Filename, when os.Chmod(pluginFile, 0755) returns an error: the file was moved/replaced between create and chmod, filesystem is FAT/exFAT without permission support, or ownership was altered externally.","commonSituations":"Installing plugins onto a Windows-formatted or network mount that ignores chmod; security software resetting file ownership; concurrent processes manipulating the plugin directory.","solutions":["Ensure the process owns the newly written plugin file (same user created it) and the filesystem supports Unix permissions.","Verify the file still exists at pluginFile and was not modified concurrently.","As a workaround, pre-set umask so created files are already executable, or chmod manually after install.","Check for external interference (AV/indexers) that could remove the file mid-install."],"exampleFix":"// before\ninstaller.Install(plugin) // fails on FAT32 USB mount\n// after\npluginDir = filepath.Join(os.Getenv(\"HOME\"), \".upterm\", \"plugins\") // use a native-FS location\ninstaller := plugins.Installer{PluginDir: pluginDir}\ninstaller.Install(plugin)","handlingStrategy":"fallback","validationCode":"// skip check on filesystems without Unix perms\nsupport := func(dir string) bool {\n    p := filepath.Join(dir, \".permtest\")\n    os.WriteFile(p, []byte(\"x\"), 0644)\n    defer os.Remove(p)\n    err := os.Chmod(p, 0755)\n    return err == nil\n}","typeGuard":null,"tryCatchPattern":"err := installer.Install(plugin)\nif err != nil && strings.Contains(err.Error(), \"set executable permission\") {\n    log.Printf(\"chmod unsupported on this filesystem; set executable bit manually\")\n    // fallback: os.Chmod(pluginFile, 0755) after remount, or relocate PluginDir\n    return nil\n}\nreturn err","preventionTips":["Install plugins on native Unix filesystems (ext4/APFS), not FAT/exFAT or some network mounts.","Avoid concurrent processes touching files in PluginDir during install.","Set a permissive umask so newly written files already carry intended modes.","If chmod fails manually, set the executable bit after install completes."],"tags":["go","filesystem","permissions","chmod","plugin-install"],"backgroundTag":"chmod-operation-not-permitted","analyzedSha":"d624239058997c80118eaebe2e7f8331b3c765e0","analyzedAt":"2026-09-02T22:38:22.007Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}