{"record":{"id":"e493ef0df3edc504","repo":"matryer/xbar","slug":"missing-xbar-title","errorCode":null,"errorMessage":"missing xbar.title","messagePattern":"missing xbar\\.title","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/metadata/plugin_metadata.go","lineNumber":71,"sourceCode":"\t// Dependencies are a list of explicit dependencies this plugin requires to run.\n\tDependencies []string `json:\"dependencies\"`\n\t// AboutURL is the public URL to learn more about the plugin, including\n\t// to contact the author.\n\tAboutURL string `json:\"aboutURL\"`\n\t// LastUpdated is when this data was last updated.\n\tLastUpdated time.Time `json:\"lastUpdated\"`\n\t// Vars are the configurable values for this Plugin.\n\tVars []PluginVar `json:\"vars\"`\n\n\t// ProcessingNotes is a list of errors/warnings/notes that are set during\n\t// the processing of this plugin.\n\tProcessingNotes []string `json:\"processingNotes\"`\n}\n\n// Validate checks the plugin data.\nfunc (p Plugin) Validate() error {\n\tif p.Title == \"\" {\n\t\treturn errors.New(\"missing xbar.title\")\n\t}\n\tif p.Desc == \"\" {\n\t\treturn errors.New(\"missing xbar.desc\")\n\t}\n\tif !HasImage(p.ImageURL) {\n\t\treturn errors.New(\"missing xbar.image\")\n\t}\n\tif len(p.Authors) == 0 {\n\t\treturn errors.New(\"missing xbar.author\")\n\t}\n\treturn nil // ok\n}\n\n// NiceDesc gets a nice description.\nfunc (p Plugin) NiceDesc() string {\n\tif p.Desc == \"\" {\n\t\treturn p.Title\n\t}","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/matryer/xbar/blob/d624239058997c80118eaebe2e7f8331b3c765e0/pkg/metadata/plugin_metadata.go#L53-L89","documentation":"Plugin.Validate enforces that a plugin's directory metadata contains a non-empty xbar.title value. The title is the plugin's display name in the xbar directory/UI, so a plugin without one is considered invalid and rejected. This is the first check in Validate, so it fires before any other missing-field errors.","triggerScenarios":"Calling Plugin.Validate (or code paths that call it, such as metadata parsing/validation pipelines) on a Plugin struct whose Title field is empty because the plugin source lacks an <xbar.title>...</xbar.title> comment or the field was never populated.","commonSituations":"Plugin authors forgetting the xbar.title metadata comment when creating a new plugin; title stripped by a template or generator; metadata parsed from a file missing the comment due to an editor or linter removal; programmatically built Plugin structs with Title left as the zero value.","solutions":["Add an <xbar.title>My Plugin Name</xbar.title> comment block to the plugin script","Set the Title field on the Plugin struct before calling Validate","Re-parse the plugin metadata with Parse after fixing the source so Title is populated"],"exampleFix":"// before (plugin script metadata)\n// <xbar.title></xbar.title>\n// after\n// <xbar.title>CPU Monitor</xbar.title>","handlingStrategy":"validation","validationCode":"func hasTitle(src string) bool {\n\treturn regexp.MustCompile(`(?s)<xbar\\.title>\\s*\\S.*?</xbar\\.title>`).MatchString(src)\n}","typeGuard":"func hasValidTitle(p metadata.Plugin) bool {\n\treturn strings.TrimSpace(p.Title) != \"\"\n}","tryCatchPattern":"if err := plugin.Validate(); err != nil {\n\tif err.Error() == \"missing xbar.title\" {\n\t\treturn fmt.Errorf(\"plugin %s: add an <xbar.title> comment block: %w\", path, err)\n\t}\n\treturn err\n}","preventionTips":["Start every plugin from a template containing all four required metadata blocks (title, desc, image, author)","Run Validate in CI for every plugin before publishing","Never leave metadata comment values empty","Lint plugin scripts for required <xbar.*> blocks"],"tags":["metadata","validation","plugin","go"],"backgroundTag":"missing-metadata-field","analyzedSha":"d624239058997c80118eaebe2e7f8331b3c765e0","analyzedAt":"2026-09-02T22:38:22.007Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}