{"record":{"id":"d65bbdfcf82e4fde","repo":"glanceapp/glance","slug":"search-bang-d-has-no-shortcut","errorCode":null,"errorMessage":"search bang #%d has no shortcut","messagePattern":"search bang #(.+?) has no shortcut","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/widget-search.go","lineNumber":62,"sourceCode":"\twidget.withTitle(\"Search\").withError(nil)\n\n\tif widget.SearchEngine == \"\" {\n\t\twidget.SearchEngine = \"duckduckgo\"\n\t}\n\n\tif widget.Placeholder == \"\" {\n\t\twidget.Placeholder = \"Type here to search…\"\n\t}\n\n\tif url, ok := searchEngines[widget.SearchEngine]; ok {\n\t\twidget.SearchEngine = url\n\t}\n\n\twidget.SearchEngine = convertSearchUrl(widget.SearchEngine)\n\n\tfor i := range widget.Bangs {\n\t\tif widget.Bangs[i].Shortcut == \"\" {\n\t\t\treturn fmt.Errorf(\"search bang #%d has no shortcut\", i+1)\n\t\t}\n\n\t\tif widget.Bangs[i].URL == \"\" {\n\t\t\treturn fmt.Errorf(\"search bang #%d has no URL\", i+1)\n\t\t}\n\n\t\twidget.Bangs[i].URL = convertSearchUrl(widget.Bangs[i].URL)\n\t}\n\n\twidget.cachedHTML = widget.renderTemplate(widget, searchWidgetTemplate)\n\treturn nil\n}\n\nfunc (widget *searchWidget) Render() template.HTML {\n\treturn widget.cachedHTML\n}\n","sourceCodeStart":44,"sourceCodeEnd":79,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-search.go#L44-L79","documentation":"Returned by searchWidget's config validation (internal/glance/widget-search.go:62) when a bangs[] entry in glance.yml lacks a shortcut key. Bangs are the '!g query'-style shortcuts; each needs both shortcut and URL. Validation runs at widget init, so a single bad entry prevents the whole search widget from rendering. The message includes the 1-based position of the offending bang.","triggerScenarios":"A bangs list item defining only url: (or with the shortcut key misspelled as 'key:'/'trigger:'), or an item that is an empty map. Example: bangs: [{ url: https://duckduckgo.com/?q=QUERY }].","commonSituations":"Copy-pasting bang config from docs and deleting/renaming the shortcut line; assuming the URL domain becomes the shortcut implicitly; indentation making shortcut a sibling of the bang item instead of inside it.","solutions":["Add the shortcut key to the offending bang (the message's #N tells you which item): shortcut: g","Check YAML indentation — shortcut and url must be keys of the same bang map","Remove incomplete bang entries entirely"],"exampleFix":"// before (glance.yml)\nwidget:\n  type: search\n  bangs:\n    - url: https://github.com/search?q=QUERY\n// after\nwidget:\n  type: search\n  bangs:\n    - shortcut: gh\n      url: https://github.com/search?q=QUERY","handlingStrategy":"validation","validationCode":"// Validate bangs config before startup\nfor i, b := range bangs {\n    if b.Shortcut == \"\" {\n        return fmt.Errorf(\"bang %d missing shortcut\", i)\n    }\n}","typeGuard":null,"tryCatchPattern":"// Go: config validation fails at init; render-time handling is unnecessary — fix glance.yml","preventionTips":["Every bangs entry needs both shortcut and url keys","Use the error's #N to jump straight to the bad entry","Validate YAML with a linter"],"tags":["search","config","validation","yaml"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}