{"record":{"id":"6decccd038f16022","repo":"glanceapp/glance","slug":"w-request-failed-w","errorCode":null,"errorMessage":"%w: request failed: %w","messagePattern":"%w: request failed: %w","errorType":"exception","errorClass":"errNoContent","httpStatus":null,"severity":"error","filePath":"internal/glance/widget-extension.go","lineNumber":132,"sourceCode":"\tdefault:\n\t\treturn template.HTML(\"<pre>\" + html.EscapeString(string(content)) + \"</pre>\")\n\t}\n}\n\nfunc fetchExtension(options extensionRequestOptions) (extension, error) {\n\trequest, _ := http.NewRequest(\"GET\", options.URL, nil)\n\tif len(options.Parameters) > 0 {\n\t\trequest.URL.RawQuery = options.Parameters.toQueryString()\n\t}\n\n\tfor key, value := range options.Headers {\n\t\trequest.Header.Add(key, value)\n\t}\n\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tslog.Error(\"Failed fetching extension\", \"url\", options.URL, \"error\", err)\n\t\treturn extension{}, fmt.Errorf(\"%w: request failed: %w\", errNoContent, err)\n\t}\n\n\tdefer response.Body.Close()\n\n\tbody, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\tslog.Error(\"Failed reading response body of extension\", \"url\", options.URL, \"error\", err)\n\t\treturn extension{}, fmt.Errorf(\"%w: could not read body: %w\", errNoContent, err)\n\t}\n\n\textension := extension{}\n\n\tif response.Header.Get(extensionHeaderTitle) == \"\" {\n\t\textension.Title = \"Extension\"\n\t} else {\n\t\textension.Title = response.Header.Get(extensionHeaderTitle)\n\t}\n","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-extension.go#L114-L150","documentation":"The HTTP request to the extension URL failed at the transport level (DNS failure, connection refused, TLS error, timeout) and the error wraps errNoContent, so the widget renders an empty state. The URL and error are also logged via slog before returning.","triggerScenarios":"http.DefaultClient.Do failing: unreachable host, DNS name not resolving, self-signed certificate rejected, server dropping the connection.","commonSituations":"Extension server down or moved; internal DNS not resolvable from where glance runs; self-signed TLS cert (Go rejects unless trusted); firewalled port; extension endpoint behind VPN that is off.","solutions":["curl the exact extension URL from the glance host to see the transport error","Fix DNS/hosts entries or use an IP/FQDN that resolves from the glance container","For self-signed certs, add the CA to the system trust store of the glance container","If the server is slow, ensure it responds within the default client's timeout budget"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"ext, err := fetchExtension(opts)\nif err != nil {\n    if errors.Is(err, errNoContent) {\n        // render last cached HTML instead of an empty panel\n        return widget.lastGoodExtension, nil\n    }\n    return extension{}, err\n}","preventionTips":["Host extensions close to glance (same network) to avoid DNS/TLS flakiness","Trust internal CAs in the glance container when extensions use self-signed certs","Keep extension endpoints health-checked so outages are visible before widgets break"],"tags":["extension","network","tls","dns"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}