| 1 | # Kubo changelog v0.42 |
| 2 | |
| 3 | <a href="https://ipshipyard.com/"><img align="right" src="https://github.com/user-attachments/assets/39ed3504-bb71-47f6-9bf8-cb9a1698f272" /></a> |
| 4 | |
| 5 | This release was brought to you by the [Shipyard](https://ipshipyard.com/) team. |
| 6 | |
| 7 | - [v0.42.0](#v0420) |
| 8 | |
| 9 | ## v0.42.0 |
| 10 | |
| 11 | - [Overview](#overview) |
| 12 | - [🔦 Highlights](#-highlights) |
| 13 | - [🎯 Announce CIDs on demand with `ipfs provide once`](#-announce-cids-on-demand-with-ipfs-provide-once) |
| 14 | - [🧩 Export and import partial CARs with `--local-only`](#-export-and-import-partial-cars-with---local-only) |
| 15 | - [⚙️ `Provide.DHT.Interval=0` no longer disables providing](#%EF%B8%8F-providedhtinterval0-no-longer-disables-providing) |
| 16 | - [🐛 Fixed pin operations hanging under pinned reprovide strategies](#-fixed-pin-operations-hanging-under-pinned-reprovide-strategies) |
| 17 | - [🐛 Smoother first-run upgrades from very old repos](#-smoother-first-run-upgrades-from-very-old-repos) |
| 18 | - [🐛 Reliable shutdown and container health checks](#-reliable-shutdown-and-container-health-checks) |
| 19 | - [🚨 ERROR log for listeners blocked by `Swarm.AddrFilters` or `Addresses.NoAnnounce`](#-error-log-for-listeners-blocked-by-swarmaddrfilters-or-addressesnoannounce) |
| 20 | - [📊 OpenTelemetry: scope info now exposed as labels](#-opentelemetry-scope-info-now-exposed-as-labels) |
| 21 | - [🔧 Cleaner progress bars](#-cleaner-progress-bars) |
| 22 | - [📦️ Dependency updates](#-dependency-updates) |
| 23 | - [📝 Changelog](#-changelog) |
| 24 | - [👨👩👧👦 Contributors](#-contributors) |
| 25 | |
| 26 | ### Overview |
| 27 | |
| 28 | ### 🔦 Highlights |
| 29 | |
| 30 | #### 🎯 Announce CIDs on demand with `ipfs provide once` |
| 31 | |
| 32 | `ipfs provide once <cid>...` announces CIDs to the routing system immediately, without waiting for the next scheduled reprovide. Use it when you want fine-grained control over when specific CIDs are announced. |
| 33 | |
| 34 | CIDs can be streamed in on stdin, so you can pipe arbitrarily large lists without growing daemon memory: |
| 35 | |
| 36 | ```sh |
| 37 | # Announce every locally pinned CID. |
| 38 | ipfs pin ls | awk '{print $1}' | ipfs provide once |
| 39 | ``` |
| 40 | |
| 41 | ```sh |
| 42 | # Announce every block reachable from a root (here, ~350 GiB of Wikipedia). |
| 43 | ipfs refs -r bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze | ipfs provide once |
| 44 | ``` |
| 45 | |
| 46 | In a terminal, the command shows a running count of queued CIDs. With `--enc=json` it emits one `{"Queued":"<cid>"}` line per CID, so downstream scripts can consume events as they arrive. |
| 47 | |
| 48 | `ipfs routing provide` keeps working but is deprecated. See `ipfs provide once --help` for usage and migration notes. |
| 49 | |
| 50 | #### 🧩 Export and import partial CARs with `--local-only` |
| 51 | |
| 52 | `ipfs dag export --local-only` writes a CAR with only the blocks you have locally; any missing blocks (and their subtrees) are skipped instead of failing the export. `ipfs dag import --local-only` reads such a partial CAR without trying to pin its roots. |
| 53 | |
| 54 | This is useful when: |
| 55 | |
| 56 | - you want to share part of a DAG (for example an MFS tree) that is only partly cached locally |
| 57 | - you fetched a partial CAR from a gateway that supports [IPIP-0402](https://specs.ipfs.tech/ipips/ipip-0402/) and want to add what you got to your local store |
| 58 | |
| 59 | `--local-only` sets the matching companion flag automatically: on export it implies `--offline`; on import it implies `--pin-roots=false`. See `ipfs dag export --help` and `ipfs dag import --help` for details. |
| 60 | |
| 61 | #### ⚙️ `Provide.DHT.Interval=0` no longer disables providing |
| 62 | |
| 63 | `Provide.DHT.Interval=0` now disables only the periodic reprovide schedule. New CIDs still announce via fast-provide-root and `ipfs provide once`. To fully disable providing, set [`Provide.Enabled=false`](https://github.com/ipfs/kubo/blob/master/docs/config.md#provideenabled). |
| 64 | |
| 65 | > [!IMPORTANT] |
| 66 | > The daemon now refuses to start when `Provide.DHT.Interval=0` is set without an explicit [`Provide.Enabled`](https://github.com/ipfs/kubo/blob/master/docs/config.md#provideenabled). Operators upgrading from an earlier kubo version must opt in to one of the two semantics: |
| 67 | > |
| 68 | > - `Provide.Enabled=false` to fully disable providing (the previous behaviour of `Interval=0`). |
| 69 | > - `Provide.Enabled=true` to keep ad-hoc providing while skipping the periodic reprovide schedule. |
| 70 | > |
| 71 | > The startup error names both options. Pick the one that matches your intent. |
| 72 | |
| 73 | #### 🐛 Fixed pin operations hanging under pinned reprovide strategies |
| 74 | |
| 75 | `ipfs pin ls`, `ipfs add`, and other pin-touching operations could block for hours on nodes running with [`Provide.Strategy`](https://github.com/ipfs/kubo/blob/master/docs/config.md#providestrategy) set to `pinned`, `roots`, or `pinned+mfs` (including `+unique` / `+entities` variants). The pin index held a read lock for the entire reprovide cycle, which on large pinsets takes many hours. Any pin operation issued during that window blocked, and further `pin ls` / `ipfs add` calls piled up behind it until the cycle finished. |
| 76 | |
| 77 | The pinner now snapshots the index under the read lock and releases it before the reprovider starts, so pin operations are no longer blocked by the reprovide cycle. The default `Provide.Strategy=all` was not affected. |
| 78 | |
| 79 | #### 🐛 Smoother first-run upgrades from very old repos |
| 80 | |
| 81 | The one-time migration for repos from `go-ipfs` or Kubo older than v0.27 now retries across several gateways with HTTP timeouts, so a single slow or blocked gateway no longer hangs the daemon. Set [`Migration.DownloadSources`](https://github.com/ipfs/kubo/blob/master/docs/config.md#migrationdownloadsources) to use your own gateway list. |
| 82 | |
| 83 | #### 🐛 Reliable shutdown and container health checks |
| 84 | |
| 85 | Sending `SIGTERM` or `SIGINT` to kubo could leave the daemon stuck "half-shutdown": internal subsystems had stopped, but the process kept running and answering the RPC API. Docker and Kubernetes health checks reported the node as healthy while it had quietly stopped serving content. Recovery required a manual `docker restart`. Separately, the pinner could log a `pebble: closed` panic trace when the datastore closed before ongoing pin operations finished. |
| 86 | |
| 87 | What changed: |
| 88 | |
| 89 | - **Bounded shutdown.** A new [`Internal.ShutdownTimeout`](https://github.com/ipfs/kubo/blob/master/docs/config.md#internalshutdowntimeout) caps how long a stuck shutdown can run, so a zombie daemon recovers instead of staying half-alive. Routine shutdowns finish in seconds; this is a belt-and-suspenders ceiling against unknown bugs and future regressions. The 12-hour default is high enough that no real-world deployment hits it and low enough to recycle a stuck node well before its DHT provider records expire (22 hours). On expiry, the daemon logs which subsystem failed and exits with status `1`. Set `0` to disable. |
| 90 | |
| 91 | - **`ipfs diag healthy` subcommand.** Returns non-zero as soon as shutdown begins, even if the RPC API still answers. The kubo Docker image's `HEALTHCHECK` now uses it, so under `--restart=on-failure` or a Kubernetes liveness probe a half-shutdown daemon is recycled within seconds. |
| 92 | |
| 93 | - **Pinner shuts down cleanly.** The pinner cancels and waits for ongoing pin work before the datastore closes, removing the `pebble: closed` panic trace from shutdown logs. |
| 94 | |
| 95 | - **DHT provider deadlines.** `ipfs provide stat` now returns promptly when the caller cancels, instead of blocking on a slow keystore lookup (previously seen at over an hour). Each provider record sent to a peer is capped by [`Provide.DHT.SendProviderRecordTimeout`](https://github.com/ipfs/kubo/blob/master/docs/config.md#providedhtsendproviderrecordtimeout), so an unresponsive peer cannot stall a reprovide cycle. |
| 96 | |
| 97 | #### 🚨 ERROR log for listeners blocked by `Swarm.AddrFilters` or `Addresses.NoAnnounce` |
| 98 | |
| 99 | Kubo now logs an ERROR when an [`Addresses.Swarm`](https://github.com/ipfs/kubo/blob/master/docs/config.md#addressesswarm) listener is covered by a rule in [`Swarm.AddrFilters`](https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmaddrfilters) (Kubo will reject every incoming connection to it) or [`Addresses.NoAnnounce`](https://github.com/ipfs/kubo/blob/master/docs/config.md#addressesnoannounce) (Kubo will not advertise it to other peers). Each line names the listener, the matching rule, and the field to remove it from. This catches silent misconfigurations like a `/ip4/127.0.0.1/tcp/.../ws` listener behind a local reverse proxy that stops working once `/ip4/127.0.0.0/ipcidr/8` lands in `Swarm.AddrFilters` (for example via the [`server` profile](https://github.com/ipfs/kubo/blob/master/docs/config.md#server-profile)). See the [reverse-proxy override row](https://github.com/ipfs/kubo/blob/master/docs/config.md#overriding-specific-entries) for the fix. |
| 100 | |
| 101 | #### 📊 OpenTelemetry: scope info now exposed as labels |
| 102 | |
| 103 | The Prometheus endpoint no longer emits the `otel_scope_info` metric. Each metric now carries `otel_scope_name`, `otel_scope_version`, and `otel_scope_schema_url` labels identifying the instrumentation library that produced it. Update dashboards or queries that read `otel_scope_info` to consume these labels instead. See [`docs/metrics.md`](https://github.com/ipfs/kubo/blob/master/docs/metrics.md) for details. |
| 104 | |
| 105 | #### 🔧 Cleaner progress bars |
| 106 | |
| 107 | `ipfs add`, `ipfs cat`, and `ipfs get` now hide their progress bar when stderr is piped or redirected, so a command like `ipfs add file 2> log.txt` no longer fills the log with progress-bar noise. Pass `--progress=true` to force the bar on, or `--progress=false` to hide it. |
| 108 | |
| 109 | `ipfs dag export` and `ipfs dag stat` now correctly recognize MSYS2 and Git Bash terminals on Windows. Previously the bar was suppressed there even when running interactively. |
| 110 | |
| 111 | #### 📦️ Dependency updates |
| 112 | |
| 113 | - update `go-libp2p-pubsub` to [v0.16.0](https://github.com/libp2p/go-libp2p-pubsub/releases/tag/v0.16.0) |
| 114 | - update `go-libp2p-kad-dht` to [v0.40.0](https://github.com/libp2p/go-libp2p-kad-dht/releases/tag/v0.40.0) (incl. [v0.39.2](https://github.com/libp2p/go-libp2p-kad-dht/releases/tag/v0.39.2)) |
| 115 | - update `go-fuse/v2` to [v2.10.1](https://github.com/hanwen/go-fuse/releases/tag/v2.10.1) |
| 116 | - update `cheggaaa/pb` to [v3.1.7](https://github.com/cheggaaa/pb/releases/tag/v3.1.7) |
| 117 | - update `boxo` to [v0.40.0](https://github.com/ipfs/boxo/releases/tag/v0.40.0) |
| 118 | |
| 119 | ### 📝 Changelog |
| 120 | |
| 121 | ### 👨👩👧👦 Contributors |