Merged
Conversation
p-linnane
approved these changes
Apr 23, 2026
Contributor
|
🤖 An automated task has requested bottles to be published to this PR. Caution Please do not push to this PR branch before the bottle commits have been pushed, as this results in a state that is difficult to recover from. If you need to resolve a merge conflict, please use a merge commit. Do not force-push to this PR branch. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Created by
brew bumpCreated with
brew bump-formula-pr.Details
release notes
ipfs cid inspectcommand--cid-basefixes across all commandsipfs updatecommandProvide.Strategymodifiers:+uniqueand+entitiespin addandpin updatenow fast-provide root CID--fast-provide-dagflag for fine-tuned provide controlProvide.StrategyparsingProvide.Strategyipfs object patchvalidates UnixFS node typesserverprofile no longer announces loopback and non-public IPv6 addressesOverview
🔦 Highlights
🗑️ Faster Provide Queue Disk Reclamation
Nodes with significant amount of data and DHT provide sweep enabled (
Provide.DHT.SweepEnabled, the default since Kubo 0.39) could see theirdatastore/directory grow continuously. Each reprovide cycle rewrote the provider keystore inside the shared repo datastore, generating tombstones faster than the storage engine could compact them, and in default configuration Kubo was slow to reclaim this space.The provider keystore now lives in a dedicated datastore under
$IPFS_PATH/provider-keystore/. After each reprovide cycle the old datastore is removed from disk entirely, so space is reclaimed immediately regardlessof storage backend.
On first start after upgrading, stale keystore data is cleaned up from the shared datastore automatically.
To learn more, see kubo#11096, kubo#11198, and go-libp2p-kad-dht#1233.
✨ New
ipfs cid inspectcommandNew subcommand for breaking down a CID into its components. Works offline, supports
--enc=json.See
ipfs cid --helpfor all CID-related commands.🔤
--cid-basefixes across all commands--cid-baseis now respected by every command that outputs CIDs. Previouslyblock stat,block put,block rm,dag stat,refs local,pin remote, andfiles chrootignored the flag.CIDv0 values are now auto-upgraded to CIDv1 when a non-base58btc base is requested, because CIDv0 can only be represented in base58btc.
🔄 Built-in
ipfs updatecommandKubo now ships with a built-in
ipfs updatecommand that downloads release binaries from GitHub and swaps the current one in place. It supersedes the externalipfs-updatetool, deprecated since v0.37.See
ipfs update --helpfor the available subcommands (check,versions,install,revert,clean).🖥️ WebUI Improvements
IPFS Web UI has been updated to v4.12.0.
IPv6 peer geolocation and Peers screen optimizations
The Peers screen now resolves IPv6 addresses to geographic locations, and the geolocation database has been updated to
GeoLite2-City-CSV_20260220. (ipfs-geoip v9.3.0)Peer locations load faster thanks to UX optimizations in the underlying ipfs-geoip library.
🔧 Correct provider addresses for custom HTTP routing
Nodes using custom routing (
Routing.Type=custom) with IPIP-526 could end up publishing unresolved0.0.0.0addresses in provider records. Addresses are now resolved at provide-time, and when AutoNAT V2 has confirmed publicly reachable addresses, those are preferred automatically. See #11213.🔀
Provide.Strategymodifiers:+uniqueand+entitiesExperimental opt-in optimizations for content providers with large repositories where multiple recursive pins share most of their DAG structure (e.g. append-only datasets, versioned archives like dist.ipfs.tech).
+unique: bloom filter dedup across recursive pins. Shared subtrees are traversed only once per reprovide cycle instead of once per pin, cutting I/O from O(pins * blocks) to O(unique blocks) at ~4 bytes/CID.+entities: announces only entity roots (files, directories, HAMT shards), skipping internal file chunks. Far fewer DHT provider records while keeping all content discoverable by file/directory CID. Implies+unique.Example:
Provide.Strategy = "pinned+mfs+entities"The default
Provide.Strategy=allis unchanged. SeeProvide.Strategyfor configuration details and caveats.The bloom filter precision is tunable via
Provide.BloomFPRate(default ~1 false positive per 4.75M lookups, ~4 bytes per CID).📌
pin addandpin updatenow fast-provide root CIDipfs pin addandipfs pin updateannounce the pinned root CID to the routing system immediately after pinning, same asipfs addandipfs dag import. This matters for selective strategies likepinned+mfs, where previously the root CID was not announced until the next reprovide cycle (seeProvide.DHT.Interval). With the defaultProvide.Strategy=all, the blockstore already provides every block on write, so this is a no-op.Both commands now accept
--fast-provide-root,--fast-provide-dag, and--fast-provide-waitflags, matchingipfs addandipfs dag import. SeeImportfor defaults and configuration.🌳 New
--fast-provide-dagflag for fine-tuned provide controlUsers with a custom
Provide.Strategy(e.g.pinned,pinned+mfs+entities) now have finer control over which CIDs are announced immediately onipfs add,ipfs dag import,ipfs pin add, andipfs pin update.By default, only the root CID is provided right away (
--fast-provide-root=true). Child blocks are deferred until the next reprovide cycle. This keeps bulk imports fast and avoids overwhelming online nodes with provide traffic.Pass
--fast-provide-dag=true(or setImport.FastProvideDAG) to provide the full DAG immediately during add, using the activeProvide.Strategyto determine scope.Provide.Strategy=all(default) is unaffected. It provides every block at the blockstore level regardless of this flag.🛡️ Hardened
Provide.StrategyparsingUnknown strategy tokens (e.g. typo
"uniuqe"), malformed delimiters ("pinned+"), and invalid combinations ("all+pinned") now produce a clear error at startup instead of being silently ignored.🔧 Filestore now respects
Provide.StrategyBlocks added via the filestore or urlstore (
ipfs add --nocopy) used to ignoreProvide.Strategyand were always announced at write time. The filestore is now gated on the strategy the same way the regular blockstore is, so selective strategies get the same fast-provide knobs for filestore-backed content that they already had for regularipfs add.🛡️
ipfs object patchvalidates UnixFS node typesAs part of the ongoing deprecation of the legacy
ipfs objectAPI (which predates HAMTShard directories and CIDv1), theadd-linkandrm-linksubcommands now validate the root node before mutating it.These commands operate at the raw
dag-pblevel and can only safely mutate small, flat UnixFS directories. They are unable to update UnixFS metadata (HAMT bitfields, fileBlocksizes), so using them on files or sharded directories would silently produce invalid DAGs. This is now rejected:Blocksizes, content lost on read-back)dag-pbnodes: rejected by defaultUse
ipfs filescommands (mkdir,cp,rm,mv) instead. They handle all directory types correctly, including large sharded directories.A
--allow-non-unixfsflag is available on bothipfs object patchcommands to bypass validation.🔗 MFS: fixed CidBuilder preservation
ipfs filescommands now correctly preserve the configured CID version and hash function (Import.CidVersion,Import.HashFunction) in all MFS operations. Previously, theCidBuildercould be silently lost when modifying file contents, creating nested directories withmkdir -p, or restarting the daemon, causing some entries to fall back to CIDv0/sha2-256.Additionally, the MFS root directory itself now respects
Import.CidVersionandImport.HashFunctionat daemon startup. Before this fix, the root always used CIDv0/sha2-256 regardless of config. Because the MFS root CID format is now managed by these config options,ipfs files chcidno longer accepts the root path/. It continues to work on subdirectories.See boxo#1125 and kubo#11273.
📂 FUSE Mount Improvements
The FUSE implementation has been rewritten on top of
hanwen/go-fusev2, replacing the unmaintainedbazil.org/fuse. This fixes long-standing architectural limitations and aligns FUSE mounts with what standard tools expect. FUSE support is still experimental. See docs/fuse.md for setup instructions, and report problems at kubo/issues.fsyncworks. Editors (vim, emacs) and databases that callfsyncafter writing no longer get a silent no-op. Data is flushed through the open file descriptor to the DAG. The full vim save sequence (O_TRUNC + write + fsync + chmod) is tested.ftruncateworks. Tools likersync --inplacethat shrink or grow files viaftruncate(fd, size)no longer get ENOTSUP. Opening existing files withO_TRUNCalso works correctly.chmodandtouchno longer drop file content. WithMounts.StoreMode/StoreMtimeenabled, setting mode or mtime previously replaced the DAG node without preserving content links, leaving the file empty.ln -s target linknow works on/mfsand/ipns. Symlinks are stored as UnixFS TSymlink nodes, the same format used byipfs add./ipfs. Files are read sequentially from the block graph instead of re-resolving from the root on every read call.catworks. Ctrl-C orkillon a read cancels in-flight block fetches instead of hanging.fusermount -ufrom outside the daemon now correctly marks the mount as inactive.allow_other./ipfsor/ipnsno longer returns an error./ipfs. Accessing a file by its CID directly under the/ipfsmount now works. This was a long-standing regression./mfsand/ipns. Renaming a file within the same directory no longer leaves the source behind./ipns/local/now correctly publishes the updated DAG. Previously IPNS publishing from the FUSE mount was silently blocked./ipnsfile handle serializes Read, Write, Flush, and Release, matching the/mfsmount./ipnsflush changes to the MFS root, preventing data loss on daemon restart./ipnsinherit the parent's CID settings instead of falling back to CIDv0.0644/0444, directories:0755/0555).Mounts.StoreMtimeandMounts.StoreMode. Writable mounts can persist mtime on file creation/write and POSIX mode onchmodfor both files and directories.touchon directories also works, which tools liketarandrsyncrely on. Both flags are off by default because they change the resulting CID. SeeMounts.StoreMtimeandMounts.StoreMode.ipfs.cidxattr on all mounts. All three mounts expose the node's CID via theipfs.cidextended attribute on files and directories. The legacyipfs_cidxattr name (used in earlier versions of/mfs) is no longer supported; useipfs.cidinstead.statfsworks. All three mounts report the free space of the volume backing the local IPFS repo, so/mfscorrectly reflects how much new data fits. Fixes macOS Finder refusing copies with "not enough free space".st_blocksandst_blksizereflect UnixFS. All three mounts fillst_blocksfrom the UnixFS file size sodu,ls -s,stat, and "size on disk" in file managers matchls -l. Directories report a nominal 1 block so tools that treat 0 as "unsupported" behave correctly.st_blksizeadvertises a chunk-aligned preferred I/O size:/mfsand/ipnsuseImport.UnixFSChunker, socp,dd, andrsyncbuffer writes at the chunker boundary;/ipfsuses a stable 1 MiB hint since published CIDs have no single chunker.fusermountsymlink;hanwen/go-fusefindsfusermount3natively.📦 CARv2 import over HTTP API
ipfs dag importof CARv2 files now works over the HTTP API. Previously it failed withoperation not supported: the HTTP multipart stream falsely advertised seek support, which go-car needs for the CARv2 payload offset. See #11253.🌐 HTTPS proxy support
Kubo's outbound HTTP clients and libp2p
/ws+/wsspeer dials have long honored the standardHTTPS_PROXY,HTTP_PROXY, andNO_PROXYenvironment variables; this release extends the WebSocket transport to also accepthttps://proxy URLs (TLS to the proxy itself), matching what Kubo's HTTP clients already supported. Seedocs/environment-variables.md.🛡️
serverprofile no longer announces loopback and non-public IPv6 addressesThe opt-in
serverprofile now also blocks IPv4 loopback (127.0.0.0/8) and the IANA-reserved0000::/3IPv6 block. Since v0.40.0, libp2p has enumerated all local interfaces, causing publicserver-profile nodes (including the default IPFS bootstrappers) to leak loopback and unallocated IPv6 prefixes like1e::/16through libp2p identify and DHT self-records (see go-libp2p#3460).Default-configured nodes are unaffected. To pick up the new entries on an existing
server-profile node:$ ipfs config profile apply serverThe command is idempotent. See the
serverprofile docs for the full filter list, RFC references, and override guidance.🐹 Go 1.26, Once More with Feeling
Kubo first shipped with Go 1.26 in v0.40.0, but v0.40.1 had to downgrade to Go 1.25 because of a Windows crash in Go's overlapped I/O layer (#11214). Go 1.26.2 fixes that regression upstream (golang/go#78041), so Kubo is back on Go 1.26 across all platforms.
You should see lower memory usage and reduced GC pauses thanks to the new Green Tea garbage collector (10-40% less GC overhead). Reading block data and API responses is faster due to
io.ReadAllimprovements (~2x faster, ~50% less memory). On 64-bit platforms, heap base address randomization adds a layer of security hardening.🐛 Fixed long-standing random daemon crashes during DHT lookups
Long-running daemons could exit with
invalid memory address or nil pointer dereferenceor similar memory errors while handling DHT traffic. The cause was a data race in the routing layer that had been latent for years:PublishQueryEventhandedQueryEvent.Responsesto subscribers (likefindprovs) by pointer while the publisher kept mutating the sameAddrInfo.Addrsslices.Two recent changes likely tipped the race into frequent visible crashes: go-multiaddr v0.15 turned
Multiaddrfrom an interface into a slice-backed struct, and Go 1.26 added heap base address randomization and a new garbage collector. Both likely made torn concurrent reads more likely to dereference unmapped memory.This release picks up the targeted fix in go-libp2p-kad-dht#1244. A broader fix for the whole class of routing publish races is proposed upstream in go-libp2p#3490.
📦️ Dependency updates
go-libp2pto v0.48.0go-libp2p-kad-dhtto v0.39.1 (incl. v0.39.0)ipfs-webuito v4.12.0gateway-conformancetests to v0.13 (incl. v0.12, v0.11)boxoto v0.39.0 (incl. v0.38.0)go-cidto v0.6.1 (pulls ingo-multibasev0.3.0 with up to 5x faster base58 encoding for CIDv0)p2p-forge/clientto v0.8.0📝 Changelog
Full Changelog
st_blocksandst_blksize(#11280) (ipfs/kubo#11280)ipfs updatecommand (#11203) (ipfs/kubo#11203)object patch(#11248) (ipfs/kubo#11248)ipfs name putfor IPNS record republishing (#11199) (ipfs/kubo#11199)View the full release notes at https://github.com/ipfs/kubo/releases/tag/v0.41.0.