@cryptotaxi247 / kubo / commits / 3a6b1ee12

feat(gateway): IPIP-0524 Gateway.AllowCodecConversion config option (#11090)

* feat(gateway): IPIP-0524 Gateway.AllowCodecConversion config option Wire up boxo's AllowCodecConversion config to control codec conversion behavior per IPIP-0524. When false (default), the gateway returns 406 Not Acceptable if the requested format doesn't match the block's codec. Clients should fetch raw blocks (`?format=raw`) and convert client-side. Ref: https://github.com/ipfs/specs/pull/524 Ref: https://github.com/ipfs/boxo/pull/1077 Ref: https://github.com/ipfs/gateway-conformance/pull/254 * chore: update boxo for improved 406 codec conversion error boxo now returns an actionable hint when codec conversion is rejected: suggests fetching raw block with ?format=raw and converting client-side. * chore: bump boxo and gateway-conformance to v0.10 * docs: add IPLD Logical Format note to AllowCodecConversion

Marcin Rataj committed Feb 6, 2026 at 02:21 UTC 3a6b1ee122c42ce71ab762340381b91706f04efa
11 files changed +62 -14
.github/workflows/gateway-conformance.yml
+4 -4
@@ -41,7 +41,7 @@ jobs:
41 steps:
42 # 1. Download the gateway-conformance fixtures
43 - name: Download gateway-conformance fixtures
44 - uses: ipfs/gateway-conformance/.github/actions/extract-fixtures@v0.9
44 + uses: ipfs/gateway-conformance/.github/actions/extract-fixtures@v0.10
45 with:
46 output: fixtures
47
@@ -93,7 +93,7 @@ jobs:
93
94 # 6. Run the gateway-conformance tests
95 - name: Run gateway-conformance tests
96 - uses: ipfs/gateway-conformance/.github/actions/test@v0.9
96 + uses: ipfs/gateway-conformance/.github/actions/test@v0.10
97 with:
98 gateway-url: http://127.0.0.1:8080
99 subdomain-url: http://localhost:8080
@@ -127,7 +127,7 @@ jobs:
127 steps:
128 # 1. Download the gateway-conformance fixtures
129 - name: Download gateway-conformance fixtures
130 - uses: ipfs/gateway-conformance/.github/actions/extract-fixtures@v0.9
130 + uses: ipfs/gateway-conformance/.github/actions/extract-fixtures@v0.10
131 with:
132 output: fixtures
133
@@ -199,7 +199,7 @@ jobs:
199
200 # 9. Run the gateway-conformance tests over libp2p
201 - name: Run gateway-conformance tests over libp2p
202 - uses: ipfs/gateway-conformance/.github/actions/test@v0.9
202 + uses: ipfs/gateway-conformance/.github/actions/test@v0.10
203 with:
204 gateway-url: http://127.0.0.1:8092
205 args: --specs "trustless-gateway,-trustless-ipns-gateway" -skip 'TestGatewayCar/GET_response_for_application/vnd.ipld.car/Header_Content-Length'
config/gateway.go
+7
@@ -10,6 +10,7 @@ const (
10 DefaultDisableHTMLErrors = false
11 DefaultExposeRoutingAPI = true
12 DefaultDiagnosticServiceURL = "https://check.ipfs.network"
13 + DefaultAllowCodecConversion = false
14
15 // Gateway limit defaults from boxo
16 DefaultRetrievalTimeout = gateway.DefaultRetrievalTimeout
@@ -73,6 +74,12 @@ type Gateway struct {
74 // be overridden per FQDN in PublicGateways.
75 DeserializedResponses Flag
76
77 + // AllowCodecConversion enables automatic conversion between codecs when
78 + // the requested format differs from the block's native codec (e.g.,
79 + // converting dag-pb or dag-cbor to dag-json). When disabled, the gateway
80 + // returns 406 Not Acceptable for codec mismatches per IPIP-524.
81 + AllowCodecConversion Flag
82 +
83 // DisableHTMLErrors disables pretty HTML pages when an error occurs. Instead, a `text/plain`
84 // page will be sent with the raw error message.
85 DisableHTMLErrors Flag
core/corehttp/gateway.go
+1
@@ -269,6 +269,7 @@ func getGatewayConfig(n *core.IpfsNode) (gateway.Config, map[string][]string, er
269 // Initialize gateway configuration, with empty PublicGateways, handled after.
270 gwCfg := gateway.Config{
271 DeserializedResponses: cfg.Gateway.DeserializedResponses.WithDefault(config.DefaultDeserializedResponses),
272 + AllowCodecConversion: cfg.Gateway.AllowCodecConversion.WithDefault(config.DefaultAllowCodecConversion),
273 DisableHTMLErrors: cfg.Gateway.DisableHTMLErrors.WithDefault(config.DefaultDisableHTMLErrors),
274 NoDNSLink: cfg.Gateway.NoDNSLink,
275 PublicGateways: map[string]*gateway.PublicGateway{},
docs/changelogs/v0.40.md
+14 -1
@@ -15,6 +15,7 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
15 - [Routing V1 HTTP API now exposed by default](#routing-v1-http-api-now-exposed-by-default)
16 - [Track total size when adding pins](#track-total-size-when-adding-pins)
17 - [IPIP-523: `?format=` takes precedence over `Accept` header](#ipip-523-format-takes-precedence-over-accept-header)
18 + - [IPIP-524: Gateway codec conversion disabled by default](#ipip-524-gateway-codec-conversion-disabled-by-default)
19 - [Improved IPNS over PubSub validation](#improved-ipns-over-pubsub-validation)
20 - [New `ipfs diag datastore` commands](#new-ipfs-diag-datastore-commands)
21 - [🚇 Improved `ipfs p2p` tunnels with foreground mode](#-improved-ipfs-p2p-tunnels-with-foreground-mode)
@@ -99,6 +100,18 @@ This ensures deterministic HTTP caching behavior and protects against CDNs that
100
101 The only breaking change is for edge cases where a client sends both a specific `Accept` header and a different `?format=` value for an explicitly supported format (`tar`, `raw`, `car`, `dag-json`, `dag-cbor`, etc.). Previously `Accept` would win. Now `?format=` always wins.
102
103 +#### IPIP-524: Gateway codec conversion disabled by default
104 +
105 +Codec conversion is now disabled by default per [IPIP-524](https://github.com/ipfs/specs/pull/524).
106 +Requests for a format that differs from the block's codec will return `406 Not Acceptable`.
107 +
108 +**Migration**: Clients should fetch raw blocks (`?format=raw` or `Accept: application/vnd.ipld.raw`)
109 +and convert client-side using libraries like [@helia/verified-fetch](https://www.npmjs.com/package/@helia/verified-fetch).
110 +
111 +This change removes gateways from a gatekeeping role: new codecs can now be adopted by clients
112 +immediately without waiting for gateway operator updates. Set [`Gateway.AllowCodecConversion`](https://github.com/ipfs/kubo/blob/master/docs/config.md#gatewayallowcodecconversion)
113 +to `true` to restore previous behavior.
114 +
115 #### Improved IPNS over PubSub validation
116
117 [IPNS over PubSub](https://specs.ipfs.tech/ipns/ipns-pubsub-router/) implementation in Kubo is now more reliable. Duplicate messages are rejected even in large networks where messages may cycle back after the in-memory cache expires.
@@ -262,7 +275,7 @@ The Inspect button now resolves `/ipfs/` and `/ipns/` paths to their final CID b
275 - update `boxo` to [v0.36.0](https://github.com/ipfs/boxo/releases/tag/v0.36.0)
276 - update `go-libp2p-kad-dht` to [v0.37.1](https://github.com/libp2p/go-libp2p-kad-dht/releases/tag/v0.37.1) (includes [v0.37.0](https://github.com/libp2p/go-libp2p-kad-dht/releases/tag/v0.37.0))
277 - update `ipfs-webui` to [v4.11.0](https://github.com/ipfs/ipfs-webui/releases/tag/v4.11.0)
265 -- update `gateway-conformance` tests to [v0.9](https://github.com/ipfs/gateway-conformance/releases/tag/v0.9.0)
278 +- update `gateway-conformance` tests to [v0.10](https://github.com/ipfs/gateway-conformance/releases/tag/v0.10.0) (incl. [v0.9](https://github.com/ipfs/gateway-conformance/releases/tag/v0.9.0))
279
280 ### 📝 Changelog
281
docs/config.md
+27
@@ -64,6 +64,7 @@ config file at runtime.
64 - [`Gateway.NoFetch`](#gatewaynofetch)
65 - [`Gateway.NoDNSLink`](#gatewaynodnslink)
66 - [`Gateway.DeserializedResponses`](#gatewaydeserializedresponses)
67 + - [`Gateway.AllowCodecConversion`](#gatewayallowcodecconversion)
68 - [`Gateway.DisableHTMLErrors`](#gatewaydisablehtmlerrors)
69 - [`Gateway.ExposeRoutingAPI`](#gatewayexposeroutingapi)
70 - [`Gateway.RetrievalTimeout`](#gatewayretrievaltimeout)
@@ -1141,6 +1142,32 @@ Default: `true`
1142
1143 Type: `flag`
1144
1145 +### `Gateway.AllowCodecConversion`
1146 +
1147 +An optional flag to enable automatic conversion between codecs when the
1148 +requested format differs from the block's native codec (e.g., converting
1149 +dag-pb or dag-cbor to dag-json).
1150 +
1151 +When disabled (the default), the gateway returns `406 Not Acceptable` for
1152 +codec mismatches, following behavior specified in
1153 +[IPIP-524](https://github.com/ipfs/specs/pull/524).
1154 +
1155 +Most users should keep this disabled unless legacy
1156 +[IPLD Logical Format](https://web.archive.org/web/20260204204727/https://ipld.io/specs/codecs/dag-pb/spec/#logical-format)
1157 +support is needed as a stop-gap while switching clients to `?format=raw`
1158 +and converting client-side.
1159 +
1160 +Instead of relying on gateway-side conversion, fetch the raw block using
1161 +`?format=raw` (`application/vnd.ipld.raw`) and convert client-side. This:
1162 +
1163 +- Allows clients to use any codec without waiting for gateway support
1164 +- Enables ecosystem innovation without gateway operator coordination
1165 +- Works with libraries like [@helia/verified-fetch](https://www.npmjs.com/package/@helia/verified-fetch) in JavaScript
1166 +
1167 +Default: `false`
1168 +
1169 +Type: `flag`
1170 +
1171 ### `Gateway.DisableHTMLErrors`
1172
1173 An optional flag to disable the pretty HTML error pages of the gateway. Instead,
docs/examples/kubo-as-a-library/go.mod
+1 -1
@@ -7,7 +7,7 @@ go 1.25
7 replace github.com/ipfs/kubo => ./../../..
8
9 require (
10 - github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412
10 + github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75
11 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
12 github.com/libp2p/go-libp2p v0.47.0
13 github.com/multiformats/go-multiaddr v0.16.1
docs/examples/kubo-as-a-library/go.sum
+2 -2
@@ -267,8 +267,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
267 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
268 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
269 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
270 -github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412 h1:nfRIkMIhetCWD8jw5ya+FY+jn9ii2c+U5gdkmSS4L1Q=
271 -github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k=
270 +github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75 h1:1UoSAzXwwgOrCZm5cu6v6bL4OGYIzcaOew9Rl6ZycqQ=
271 +github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k=
272 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
273 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
274 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
go.mod
+1 -1
@@ -21,7 +21,7 @@ require (
21 github.com/hashicorp/go-version v1.8.0
22 github.com/ipfs-shipyard/nopfs v0.0.14
23 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0
24 - github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412
24 + github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75
25 github.com/ipfs/go-block-format v0.2.3
26 github.com/ipfs/go-cid v0.6.0
27 github.com/ipfs/go-cidutil v0.1.0
go.sum
+2 -2
@@ -337,8 +337,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
337 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
338 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
339 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
340 -github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412 h1:nfRIkMIhetCWD8jw5ya+FY+jn9ii2c+U5gdkmSS4L1Q=
341 -github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k=
340 +github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75 h1:1UoSAzXwwgOrCZm5cu6v6bL4OGYIzcaOew9Rl6ZycqQ=
341 +github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k=
342 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
343 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
344 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
test/dependencies/go.mod
+1 -1
@@ -135,7 +135,7 @@ require (
135 github.com/huin/goupnp v1.3.0 // indirect
136 github.com/inconshreveable/mousetrap v1.1.0 // indirect
137 github.com/ipfs/bbloom v0.0.4 // indirect
138 - github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412 // indirect
138 + github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75 // indirect
139 github.com/ipfs/go-bitfield v1.1.0 // indirect
140 github.com/ipfs/go-block-format v0.2.3 // indirect
141 github.com/ipfs/go-cid v0.6.0 // indirect
test/dependencies/go.sum
+2 -2
@@ -296,8 +296,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
296 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
297 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
298 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
299 -github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412 h1:nfRIkMIhetCWD8jw5ya+FY+jn9ii2c+U5gdkmSS4L1Q=
300 -github.com/ipfs/boxo v0.36.1-0.20260204203152-f188f79fd412/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k=
299 +github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75 h1:1UoSAzXwwgOrCZm5cu6v6bL4OGYIzcaOew9Rl6ZycqQ=
300 +github.com/ipfs/boxo v0.36.1-0.20260205235512-2a942e3e1a75/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k=
301 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
302 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
303 github.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk=