@cryptotaxi247 / kubo / commits / 906ce802b

feat(gateway): improved error page with retrieval state details (#10950)

* feat(gateway): add DiagnosticServiceURL config - add Gateway.DiagnosticServiceURL to kubo config - pass diagnostic service URL to boxo gateway - document new config option in docs/config.md - default to https://check.ipfs.network * docs(changelog): add gateway error UX improvements to v0.38 - document improved 504 error pages with retrieval diagnostics - highlight new Gateway.DiagnosticServiceURL config option - include screenshot showing enhanced error page UX

Marcin Rataj committed Sep 8, 2025 at 19:49 UTC 906ce802bf8c619f67d9ed1242d78b1010740c09
10 files changed +41 -12
config/gateway.go
+7
@@ -9,6 +9,7 @@ const (
9 DefaultDeserializedResponses = true
10 DefaultDisableHTMLErrors = false
11 DefaultExposeRoutingAPI = false
12 + DefaultDiagnosticServiceURL = "https://check.ipfs.network"
13
14 // Gateway limit defaults from boxo
15 DefaultRetrievalTimeout = gateway.DefaultRetrievalTimeout
@@ -98,4 +99,10 @@ type Gateway struct {
99 // Requests beyond this limit receive 429 Too Many Requests with Retry-After header.
100 // A value of 0 disables the limit.
101 MaxConcurrentRequests *OptionalInteger `json:",omitempty"`
102 +
103 + // DiagnosticServiceURL is the URL for a service to diagnose CID retrievability issues.
104 + // When the gateway returns a 504 Gateway Timeout error, an "Inspect retrievability of CID"
105 + // button will be shown that links to this service with the CID appended as ?cid=<CID-to-diagnose>.
106 + // Set to empty string to disable the button.
107 + DiagnosticServiceURL *OptionalString `json:",omitempty"`
108 }
core/corehttp/gateway.go
+3
@@ -107,11 +107,13 @@ func Libp2pGatewayOption() ServeOption {
107 // Keep these constraints for security
108 DeserializedResponses: false, // Trustless-only
109 NoDNSLink: true, // No DNS resolution
110 + DisableHTMLErrors: true, // Plain text errors only
111 PublicGateways: nil,
112 Menu: nil,
113 // Apply timeout and concurrency limits from user config
114 RetrievalTimeout: cfg.Gateway.RetrievalTimeout.WithDefault(config.DefaultRetrievalTimeout),
115 MaxConcurrentRequests: int(cfg.Gateway.MaxConcurrentRequests.WithDefault(int64(config.DefaultMaxConcurrentRequests))),
116 + DiagnosticServiceURL: "", // Not used since DisableHTMLErrors=true
117 }
118
119 handler := gateway.NewHandler(gwConfig, &offlineGatewayErrWrapper{gwimpl: backend})
@@ -270,6 +272,7 @@ func getGatewayConfig(n *core.IpfsNode) (gateway.Config, map[string][]string, er
272 PublicGateways: map[string]*gateway.PublicGateway{},
273 RetrievalTimeout: cfg.Gateway.RetrievalTimeout.WithDefault(config.DefaultRetrievalTimeout),
274 MaxConcurrentRequests: int(cfg.Gateway.MaxConcurrentRequests.WithDefault(int64(config.DefaultMaxConcurrentRequests))),
275 + DiagnosticServiceURL: cfg.Gateway.DiagnosticServiceURL.WithDefault(config.DefaultDiagnosticServiceURL),
276 }
277
278 // Add default implicit known gateways, such as subdomain gateway on localhost.
docs/changelogs/v0.38.md
+11 -1
@@ -18,6 +18,16 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
18
19 ### 🔦 Highlights
20
21 +#### 🚨 Improved gateway error pages with diagnostic tools
22 +
23 +Gateway error pages now provide more actionable information during content retrieval failures. When a 504 Gateway Timeout occurs, users see detailed retrieval state information including which phase failed and a sample of providers that were attempted:
24 +
25 +> ![Improved gateway error page showing retrieval diagnostics](https://github.com/user-attachments/assets/18432c74-a5e0-4bbf-9815-7c780779dc98)
26 +>
27 +> - **[`Gateway.DiagnosticServiceURL`](https://github.com/ipfs/kubo/blob/master/docs/config.md#gatewaydiagnosticserviceurl)** (default: `https://check.ipfs.network`): Configures the diagnostic service URL. When set, 504 errors show a "Check CID retrievability" button that links to this service with `?cid=<failed-cid>` for external diagnostics. Set to empty string to disable.
28 +> - **Enhanced error details**: Timeout errors now display the retrieval phase where failure occurred (e.g., "connecting to providers", "fetching data") and up to 3 peer IDs that were attempted but couldn't deliver the content, making it easier to diagnose network or provider issues.
29 +> - **Retry button on all error pages**: Every gateway error page now includes a retry button for quick page refresh without manual URL re-entry.
30 +
31 ### 📦️ Important dependency updates
32
33 ### 📝 Changelog
@@ -26,4 +36,4 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
36
37 </details>
38
29 -### 👨‍👩‍👧‍👦 Contributors
\ No newline at end of file
39 +### 👨‍👩‍👧‍👦 Contributors
docs/config.md
+11
@@ -69,6 +69,7 @@ config file at runtime.
69 - [`Gateway.MaxConcurrentRequests`](#gatewaymaxconcurrentrequests)
70 - [`Gateway.HTTPHeaders`](#gatewayhttpheaders)
71 - [`Gateway.RootRedirect`](#gatewayrootredirect)
72 + - [`Gateway.DiagnosticServiceURL`](#gatewaydiagnosticserviceurl)
73 - [`Gateway.FastDirIndexThreshold`](#gatewayfastdirindexthreshold)
74 - [`Gateway.Writable`](#gatewaywritable)
75 - [`Gateway.PathPrefixes`](#gatewaypathprefixes)
@@ -1174,6 +1175,16 @@ Default: `""`
1175
1176 Type: `string` (url)
1177
1178 +### `Gateway.DiagnosticServiceURL`
1179 +
1180 +URL for a service to diagnose CID retrievability issues. When the gateway returns a 504 Gateway Timeout error, an "Inspect retrievability of CID" button will be shown that links to this service with the CID appended as `?cid=<CID-to-diagnose>`.
1181 +
1182 +Set to empty string to disable the button.
1183 +
1184 +Default: `"https://check.ipfs.network"`
1185 +
1186 +Type: `optionalstring` (url)
1187 +
1188 ### `Gateway.FastDirIndexThreshold`
1189
1190 **REMOVED**: this option is [no longer necessary](https://github.com/ipfs/kubo/pull/9481). Ignored since [Kubo 0.18](https://github.com/ipfs/kubo/blob/master/docs/changelogs/v0.18.md).
docs/examples/kubo-as-a-library/go.mod
+1 -2
@@ -7,7 +7,7 @@ go 1.25
7 replace github.com/ipfs/kubo => ./../../..
8
9 require (
10 - github.com/ipfs/boxo v0.34.0
10 + github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364
11 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
12 github.com/libp2p/go-libp2p v0.43.0
13 github.com/multiformats/go-multiaddr v0.16.1
@@ -82,7 +82,6 @@ require (
82 github.com/ipfs/go-ds-measure v0.2.2 // indirect
83 github.com/ipfs/go-ds-pebble v0.5.1 // indirect
84 github.com/ipfs/go-fs-lock v0.1.1 // indirect
85 - github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
85 github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect
86 github.com/ipfs/go-ipfs-pq v0.0.3 // indirect
87 github.com/ipfs/go-ipfs-redirects-file v0.1.2 // indirect
docs/examples/kubo-as-a-library/go.sum
+2 -2
@@ -287,8 +287,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
287 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
288 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
289 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
290 -github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g=
291 -github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA=
290 +github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364 h1:VdRdPlosNYdlENC0UsCxapHala/Q1Me6yBY5ChKUw7s=
291 +github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0=
292 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
293 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
294 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
go.mod
+1 -2
@@ -22,7 +22,7 @@ require (
22 github.com/hashicorp/go-version v1.7.0
23 github.com/ipfs-shipyard/nopfs v0.0.14
24 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0
25 - github.com/ipfs/boxo v0.34.0
25 + github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364
26 github.com/ipfs/go-block-format v0.2.2
27 github.com/ipfs/go-cid v0.5.0
28 github.com/ipfs/go-cidutil v0.1.0
@@ -146,7 +146,6 @@ require (
146 github.com/huin/goupnp v1.3.0 // indirect
147 github.com/ipfs/bbloom v0.0.4 // indirect
148 github.com/ipfs/go-bitfield v1.1.0 // indirect
149 - github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
149 github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect
150 github.com/ipfs/go-ipfs-pq v0.0.3 // indirect
151 github.com/ipfs/go-ipfs-redirects-file v0.1.2 // indirect
go.sum
+2 -2
@@ -354,8 +354,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
354 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
355 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
356 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
357 -github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g=
358 -github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA=
357 +github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364 h1:VdRdPlosNYdlENC0UsCxapHala/Q1Me6yBY5ChKUw7s=
358 +github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0=
359 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
360 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
361 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
test/dependencies/go.mod
+1 -1
@@ -134,7 +134,7 @@ require (
134 github.com/huin/goupnp v1.3.0 // indirect
135 github.com/inconshreveable/mousetrap v1.1.0 // indirect
136 github.com/ipfs/bbloom v0.0.4 // indirect
137 - github.com/ipfs/boxo v0.34.0 // indirect
137 + github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364 // indirect
138 github.com/ipfs/go-bitfield v1.1.0 // indirect
139 github.com/ipfs/go-block-format v0.2.2 // indirect
140 github.com/ipfs/go-cid v0.5.0 // indirect
test/dependencies/go.sum
+2 -2
@@ -332,8 +332,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
332 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
333 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
334 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
335 -github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g=
336 -github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA=
335 +github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364 h1:VdRdPlosNYdlENC0UsCxapHala/Q1Me6yBY5ChKUw7s=
336 +github.com/ipfs/boxo v0.34.1-0.20250908170437-7d2493027364/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0=
337 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
338 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
339 github.com/ipfs/go-block-format v0.2.2 h1:uecCTgRwDIXyZPgYspaLXoMiMmxQpSx2aq34eNc4YvQ=