{"record":{"id":"2fabb3de7c098247","repo":"multica-ai/multica","slug":"plugin-directory-q-is-not-empty","errorCode":null,"errorMessage":"plugin directory %q is not empty","messagePattern":"plugin directory %q is not empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_plugin.go","lineNumber":82,"sourceCode":"\tpluginInitCmd.Flags().String(\"key\", \"dev.local.example-skill\", \"Reverse-DNS Plugin key\")\n\tpluginInitCmd.Flags().String(\"name\", \"Example Skill\", \"Plugin and Skill display name\")\n\tpluginInitCmd.Flags().String(\"publisher\", \"private.local\", \"Private publisher label\")\n\tpluginValidateCmd.Flags().String(\"output\", \"json\", \"Output format: table or json\")\n\tpluginPackCmd.Flags().String(\"output\", \"\", \"Output ZIP path (required)\")\n\tpluginPackCmd.Flags().String(\"format\", \"table\", \"Result format: table or json\")\n\tpluginInstallCmd.Flags().String(\"workspace\", \"\", \"Workspace ID, slug, or ID prefix\")\n\tpluginInstallCmd.Flags().String(\"output\", \"json\", \"Output format: table or json\")\n\tpluginListCmd.Flags().String(\"workspace\", \"\", \"Workspace ID, slug, or ID prefix\")\n\tpluginListCmd.Flags().String(\"output\", \"table\", \"Output format: table or json\")\n\tpluginStatusCmd.Flags().String(\"workspace\", \"\", \"Workspace ID, slug, or ID prefix\")\n\tpluginStatusCmd.Flags().String(\"output\", \"json\", \"Output format: table or json\")\n}\n\nfunc runPluginInit(cmd *cobra.Command, args []string) error {\n\tdir := filepath.Clean(args[0])\n\tentries, err := os.ReadDir(dir)\n\tif err == nil && len(entries) > 0 {\n\t\treturn fmt.Errorf(\"plugin directory %q is not empty\", dir)\n\t}\n\tif err != nil && !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"inspect plugin directory: %w\", err)\n\t}\n\tkey, _ := cmd.Flags().GetString(\"key\")\n\tname, _ := cmd.Flags().GetString(\"name\")\n\tpublisher, _ := cmd.Flags().GetString(\"publisher\")\n\tmanifest := plugincontract.Manifest{\n\t\tAPIVersion: plugincontract.APIVersionV1,\n\t\tKind:       plugincontract.KindPlugin,\n\t\tMetadata: plugincontract.Metadata{\n\t\t\tKey: key, Name: name, Description: \"A workspace-private declarative Skill Plugin.\", Version: \"0.1.0\", Publisher: publisher,\n\t\t},\n\t\tCompatibility: plugincontract.Compatibility{\n\t\t\tHostAPI: \">=1.0.0 <2.0.0\",\n\t\t\tRequiredDaemonFeatures: []string{\n\t\t\t\tplugincontract.DaemonFeatureExecutionManifestV1,\n\t\t\t\tplugincontract.DaemonFeatureAgentSkillV1,","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_plugin.go#L64-L100","documentation":"Guard in `multica plugin init <dir>` (cmd_plugin.go:82): os.ReadDir on the cleaned target directory succeeded and returned at least one entry, so the scaffolder refuses to run to avoid overwriting existing files. This is a deliberate safety check, not an environment failure.","triggerScenarios":"Running `multica plugin init ./my-plugin` when ./my-plugin already contains any file or subdirectory (even dotfiles like .DS_Store or .git).","commonSituations":"Re-running init after a previous partial scaffold; pointing at an existing source folder; OS artifacts (Thumbs.db, .DS_Store) inside a directory the user believes is empty.","solutions":["Point init at a fresh, truly empty directory: `multica plugin init ./my-plugin-v2`.","If the existing content is disposable, remove it first: `rm -rf ./my-plugin && multica plugin init ./my-plugin`.","If only hidden OS files block it, delete those specifically (`find ./my-plugin -name '.DS_Store' -delete`) and retry."],"exampleFix":"// before\nmultica plugin init ./my-plugin   # dir already has plugin.yaml from earlier run\n// plugin directory \"/abs/my-plugin\" is not empty\n\n// after\nrm -rf ./my-plugin\nmultica plugin init ./my-plugin --key com.example.my-plugin --name \"My Plugin\"","handlingStrategy":"validation","validationCode":"entries, err := os.ReadDir(dir)\nif err == nil && len(entries) > 0 {\n    // refuse or clean before calling plugin init\n    if !force { return fmt.Errorf(\"refusing: %s not empty\", dir) }\n    if err := os.RemoveAll(dir); err != nil { return err }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always scaffold into a brand-new directory name.","Check emptiness yourself (including hidden files) before re-running init.","Treat a failed init as resumable by deleting the partial directory first."],"tags":["cli","filesystem","validation","plugin","go"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}