{"record":{"id":"06838249b8b86579","repo":"glanceapp/glance","slug":"parsing-url-v","errorCode":null,"errorMessage":"parsing URL: %v","messagePattern":"parsing URL: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/widget-extension.go","lineNumber":39,"sourceCode":"\twidgetBase          `yaml:\",inline\"`\n\tURL                 string               `yaml:\"url\"`\n\tFallbackContentType string               `yaml:\"fallback-content-type\"`\n\tParameters          queryParametersField `yaml:\"parameters\"`\n\tHeaders             map[string]string    `yaml:\"headers\"`\n\tAllowHtml           bool                 `yaml:\"allow-potentially-dangerous-html\"`\n\tExtension           extension            `yaml:\"-\"`\n\tcachedHTML          template.HTML        `yaml:\"-\"`\n}\n\nfunc (widget *extensionWidget) initialize() error {\n\twidget.withTitle(extensionWidgetDefaultTitle).withCacheDuration(time.Minute * 30)\n\n\tif widget.URL == \"\" {\n\t\treturn errors.New(\"URL is required\")\n\t}\n\n\tif _, err := url.Parse(widget.URL); err != nil {\n\t\treturn fmt.Errorf(\"parsing URL: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (widget *extensionWidget) update(ctx context.Context) {\n\textension, err := fetchExtension(extensionRequestOptions{\n\t\tURL:                 widget.URL,\n\t\tFallbackContentType: widget.FallbackContentType,\n\t\tParameters:          widget.Parameters,\n\t\tHeaders:             widget.Headers,\n\t\tAllowHtml:           widget.AllowHtml,\n\t})\n\n\twidget.canContinueUpdateAfterHandlingErr(err)\n\n\twidget.Extension = extension\n","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-extension.go#L21-L57","documentation":"Thrown during extension widget initialization when url.Parse rejects the configured URL. Go's url.Parse only errors on control characters or malformed escapes, so this is almost always a config typo. Note that url.Parse accepts relative URLs, so a missing scheme passes validation but fails later at fetch time.","triggerScenarios":"Extension widget's url: field contains a control character, invalid percent-escape (e.g. '%zz'), or is otherwise unparseable.","commonSituations":"Copy-pasted URL with hidden characters; YAML multi-line or special-character handling corrupting the value; percent signs in the URL not encoded.","solutions":["Rewrite the url: value by hand, quoted, in the extension widget config","Percent-encode literal % as %25 and any spaces","Include the scheme (https://) even though validation alone does not require it"],"exampleFix":"# before\n- type: extension\n  url: https://example.com/ext%zz\n# after\n- type: extension\n  url: \"https://example.com/ext%25zz\"","handlingStrategy":"validation","validationCode":"func validateExtensionURL(raw string) error {\n    if raw == \"\" {\n        return errors.New(\"URL is required\")\n    }\n    u, err := url.Parse(raw)\n    if err != nil {\n        return fmt.Errorf(\"parsing URL: %v\", err)\n    }\n    if u.Scheme != \"http\" && u.Scheme != \"https\" {\n        return fmt.Errorf(\"URL %q must start with http:// or https://\", raw)\n    }\n    return nil\n}","typeGuard":"func isHTTPURL(raw string) bool {\n    u, err := url.Parse(raw)\n    return err == nil && (u.Scheme == \"http\" || u.Scheme == \"https\") && u.Host != \"\"\n}","tryCatchPattern":"if err := widget.initialize(); err != nil {\n    slog.Error(\"extension widget disabled\", \"error\", err)\n    widget.withError(err) // render config error in place of the widget\n}","preventionTips":["Quote extension URLs in YAML and include the scheme","Add a config lint step that runs url.Parse + scheme check over all URL fields"],"tags":["extension","url","yaml","validation"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}