# MinIO AIStor EDGE.2026-03-03T18-23-09Z

Released: 2026-03-03

This EDGE release delivers significant performance improvements to distributed locking and object
reads, resolves critical concurrency and data-integrity bugs across replication, erasure, IAM, and
inventory subsystems, and closes two security vulnerabilities. It also introduces new S3-compatible
APIs, multi-NIC internode networking, and MegaRAID SMART health monitoring for enterprise storage
hardware.

---

## Downloads

### Binary Downloads

| Platform | Architecture | Download                                                                 |
| -------- | ------------ | ------------------------------------------------------------------------ |
| Linux    | amd64        | [minio](https://dl.min.io/aistor/minio/edge/linux-amd64/minio)           |
| Linux    | arm64        | [minio](https://dl.min.io/aistor/minio/edge/linux-arm64/minio)           |
| macOS    | arm64        | [minio](https://dl.min.io/aistor/minio/edge/darwin-arm64/minio)          |
| macOS    | amd64        | [minio](https://dl.min.io/aistor/minio/edge/darwin-amd64/minio)          |
| Windows  | amd64        | [minio.exe](https://dl.min.io/aistor/minio/edge/windows-amd64/minio.exe) |

### FIPS Binaries

| Platform | Architecture | Download                                                                 |
| -------- | ------------ | ------------------------------------------------------------------------ |
| Linux    | amd64        | [minio.fips](https://dl.min.io/aistor/minio/edge/linux-amd64/minio.fips) |
| Linux    | arm64        | [minio.fips](https://dl.min.io/aistor/minio/edge/linux-arm64/minio.fips) |

### Package Downloads

| Format | Architecture | Download                                                                                                                         |
| ------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| DEB    | amd64        | [minio_20260303182309.0.0_amd64.deb](https://dl.min.io/aistor/minio/edge/linux-amd64/minio_20260303182309.0.0_amd64.deb)         |
| DEB    | arm64        | [minio_20260303182309.0.0_arm64.deb](https://dl.min.io/aistor/minio/edge/linux-arm64/minio_20260303182309.0.0_arm64.deb)         |
| RPM    | amd64        | [minio-20260303182309.0.0-1.x86_64.rpm](https://dl.min.io/aistor/minio/edge/linux-amd64/minio-20260303182309.0.0-1.x86_64.rpm)   |
| RPM    | arm64        | [minio-20260303182309.0.0-1.aarch64.rpm](https://dl.min.io/aistor/minio/edge/linux-arm64/minio-20260303182309.0.0-1.aarch64.rpm) |

### Container Images

```bash
# Standard
docker pull quay.io/minio/aistor/minio:EDGE.2026-03-03T18-23-09Z
podman pull quay.io/minio/aistor/minio:EDGE.2026-03-03T18-23-09Z

# FIPS
docker pull quay.io/minio/aistor/minio:EDGE.2026-03-03T18-23-09Z.fips
podman pull quay.io/minio/aistor/minio:EDGE.2026-03-03T18-23-09Z.fips
```

---

## Security & Compliance

### Security Updates

- **Fixed unauthenticated log streaming** — `APILogsHandler`, `ErrorLogsHandler`, and
  `AuditLogsHandler` lacked authentication checks, allowing any client with network access to stream
  server logs containing bucket names, object keys, access keys, and full HTTP request/response
  details. All three endpoints now enforce authentication (#3065)
- **Fixed OpenID audience check bypass** — when the audience check returned an error, execution
  continued and valid credentials were still issued. The blast radius was limited to callers with a
  properly signed token but credentials must not be issued after a failed audience check (#3059)
- Updated `golang.org/x/net` to address GO-2026-4559 (20f14134)
- Updated dependencies to resolve `govulncheck` findings (e3c83dd6)

### Software Bill of Materials (SBOM)

This release includes comprehensive SBOM documentation in multiple formats:

- [SPDX JSON](sbom-EDGE.2026-03-03T18-23-09Z.spdx.json) - Standard SBOM format
- [CycloneDX JSON](sbom-EDGE.2026-03-03T18-23-09Z.cyclonedx.json) - Security scanner compatible
- [Go Modules](go-modules-EDGE.2026-03-03T18-23-09Z.txt) - Human-readable dependency list

---

## New Features

- **UpdateObjectEncryption API** — implements S3 in-place encryption type change, allowing objects
  to transition between SSE-S3, SSE-KMS, and no encryption without re-uploading data (#3021)
- **Multi-NIC internode networking** — adds support for multiple network interfaces to achieve
  aggregate internode bandwidth. Introduces config v3 format where NIC addresses live directly in
  pool node definitions. Existing v1/v2 configs are auto-migrated on startup (#2968)
- **MegaRAID SMART health monitoring** — adds SMART health data collection for physical drives
  behind Broadcom/LSI MegaRAID controllers (HPE ProLiant, Dell PowerEdge, Cisco UCS) via the
  `megaraid_sas` kernel driver ioctl. Previously these systems reported
  `smartMetricStatusCollectionError = 4` for all drives (#3190)
- **Kubernetes TokenReview** — adds a configurable `oidc` token validation mode via
  `MINIO_KUBERNETES_TOKEN_VALIDATION`. Unlike `tokenreview`, the `oidc` mode uses Kubernetes OIDC
  endpoints and requires no additional RBAC cluster roles (#3100)
- **Self-service password change** — new `POST /minio/admin/v3/change-my-password` endpoint lets
  users change their own password without requiring `admin:CreateUser` policy permissions.
  Administrators can block this with the new `ChangeMyPasswordAdminAction` (#2835)
- **`Prefer: return=full` header** — when a request includes `Prefer: return=full`, the server
  returns the complete object and ignores the `Range` header, responding with
  `Preference-Applied: return=full`. Enables cache/proxy layers to fetch whole objects in a
  single request (#2898)

---

## Performance Improvements

- **Write lock coalescing** — write locks are now coalesced per node, mirroring existing read-lock
  coalescing. The first writer acquires the distributed lock via RPC; subsequent writers on the same
  node queue locally with zero additional RPCs until the current holder completes, significantly
  reducing RPC traffic under heavy write workloads (#3197)
- **Batch lock refresh RPCs** — reduces distributed lock refresh traffic from N×M to M RPCs per
  cycle by coalescing all refresh calls to the same lock server into a single `BatchRefresh` RPC,
  eliminating per-lock refresh goroutines under high concurrency (#3060)
- **Direct-write GetObject for plain objects** — for unencrypted, uncompressed objects, erasure
  decoded data is streamed directly to the HTTP `ResponseWriter` without an intermediate `io.Pipe`
  or goroutine. Encrypted and compressed objects retain the existing code path (#3072)
- **Singleflight for hot metadata paths** — concurrent calls to data-usage reads, `HeadBucket` peer
  fan-outs, and multipart upload ID verification are now deduplicated via singleflight, reducing
  redundant disk and RPC operations under concurrent load (#3135)
- **Singleflight for getObjectFileInfo** — concurrent `GetObject`/`HeadObject` requests for the
  same object share a single disk fan-out across all erasure set disks instead of each independently
  querying all drives. Results are deep-cloned to prevent mutation aliasing across handlers (#3118)
- **NSScanner cache offloading** — per-bucket cache load/save and scan mode computation are now
  handled locally by each peer rather than marshaled and transferred over the wire through the
  coordinator. Reduces CPU and network overhead in large clusters (#3030)
- **Prefer-local erasure read** — fixed dead code path where the prefer-local optimization was
  bypassed in distributed mode because `Hostname()==""` is never true for URL endpoints. Now uses
  `IsLocal()` so local drives are correctly preferred for reads (#3139)

---

## Bug Fixes

### Data Integrity

- Fixed silent deletion of valid objects: three bugs composed to cause false `DeleteDanglingObject`
  on versioned erasure sets when a `CopyObject` (versionOnly=true) partially wrote a new versionID
  to only a subset of disks and a concurrent `HeadObject` polled the object. `pickLatestQuorumFilesInfo`
  now allocates a fresh error slice instead of mutating the caller's, and `writeAllMetadataWithRevert`
  correctly returns write-quorum errors regardless of the revert flag (#3230)
- Fixed `CleanAbandonedData` writing stale metadata to drives that already held current data,
  potentially corrupting object metadata on healing (#3081)
- Fixed erasure `ToFileInfo` panic on nil `PartActualSizes` — metadata written before September
  2023 or without compression may have nil `PartActualSizes`; indexing it unconditionally caused
  panics during reads of those objects (#3200)
- Fixed `GetObjectReader` data race between concurrent `Read` and `Close` calls (#3133)
- Fixed `lazyPipeReader` goroutine outliving `GetObjectReader.Close` — the background erasure read
  goroutine could access object data after cleanup functions released the namespace read lock.
  `Close` now blocks until the goroutine exits before running any cleanup (4065f3e2)
- Fixed `kvFields` substring collision on key matching — `strings.Index` caused shorter keys to
  falsely match inside longer keys (e.g. `speed=` matching within `idle_speed=`) (#3202)

### Replication

- Fixed replication config cleared in the scanner when `ListBucketTargets` fails — this dropped
  the `Config` field causing the ILM evaluator to skip the `EdgeSyncBeforeExpiry` guard and expire
  objects with non-`COMPLETED` replication status (#3201)
- Fixed replication tag filter using OR instead of AND semantics — S3 spec requires all tags in an
  `<And>` filter to match; previously an object matching any single tag was replicated (#3112)
- Fixed last-hour replication metrics merge silently dropping all receiver-side data — the merge
  accumulator was initialized from a zero-value struct instead of the receiver, producing zeroed
  remote-side replication metrics (#3117)
- Fixed `older-than` filter overflow in the replication reset handler — `days` is a
  `time.Duration` (nanoseconds) and dividing by 24 produced day counts in the trillions, making
  the filter non-functional and causing all objects to be resynced regardless of age (#3120)
- Fixed site replication concurrency: indefinite blocking when peer clusters become unreachable,
  data races on shared removal state, and missing synchronization for concurrent removal attempts
  (#2708)
- Fixed incorrect `Partial` status returned when `RemoveAll=true` and a peer is unreachable —
  local cleanup had already run so returning `Partial` caused unnecessary retry loops (#3198)

### IAM / Authentication

- Fixed IAM broadcast leader election never selecting a leader and IAM state hash never reflecting
  mutations — `globalLocalNodeName` (bare `host:port`) was compared against grid targets
  (`http://host:port`), so no node was ever elected and periodic IAM state convergence never
  triggered (#3142)
- Fixed data race on `rolesMap` reads in IAM — `HasRolePolicy`, `GetRolePolicy`,
  `IsAllowedServiceAccount`, and `IsAllowedSTS` read the map without holding `RLock()`, racing
  with the background OpenID initializer. Replaced with lock-free `xsync.Map` (#3091)
- Fixed STS policy resolution order — JWT claims are now checked before PolicyDB in `IsAllowedSTS`
  and `TemporaryAccountInfo`, preventing stale PolicyDB entries from overriding claim-based
  policies (#3138)
- Fixed race condition in `getPeerName` (#3178)
- Fixed nil pointer dereference in `PeerPolicyMappingHandler` (#3040)
- Fixed config changes being applied during rolling upgrades — newer config keys introduced by
  upgraded nodes can no longer be persisted until all nodes are upgraded and the cluster API
  version is bumped (#3169)
- Fixed LDAP and OpenID purge routines starting before the respective services are reachable,
  potentially purging valid sessions on startup (#3002)

### Tables / Delta Sharing

- Fixed Delta Sharing queries silently dropping files with deletion vectors — tables with row-level
  DELETEs returned only unaffected data files; DV presigned URLs also returned 404 because the
  binary file path was not resolved (#3105)
- Fixed Delta Sharing deletion vector descriptors not being transformed for standard clients —
  raw `storageType = "u"` (Z85-encoded) descriptors are now rewritten to `storageType = "p"`
  with presigned URLs. Absolute-path DV descriptors are rejected (#3122)
- Fixed `loadAllShards` returning 500 on concurrent namespace delete (#3150)
- Fixed orphaned `metadata.json` files left when a commit loses the CAS race — asynchronous
  cleanup now removes the superseded file (#3182)
- Fixed table transaction recovery direction — the system was rolling forward instead of back
  when recovering staged-to-live, potentially leaving tables in an inconsistent state (#2996)
- Fixed warehouse creation returning 500 instead of 409 when the name conflicts with an existing
  bucket (#3156)
- Improved error message when `mc mb` targets an existing Tables warehouse — now returns a
  descriptive conflict error instead of the generic `BucketAlreadyOwnedByYou` (#3157)
- Fixed `Always set non-nil error to result` in Delta Sharing response paths (#2992)

### Inventory

- Fixed `saveFinalJobStateWithRetry` overwriting concurrent control-plane changes — when a
  `CancelJob`, `SuspendJob`, or `PutConfig` changed job metadata between retry attempts, the
  executor's terminal state was written over the control-plane change (#3163)
- Fixed stale `Lock` field left on jobs after a `Suspend → Resume` cycle, preventing schedulers
  from claiming the job on the next cycle (#3192)
- Fixed goroutine leak and incorrect NDJSON manifest key names in inventory output (#2938)
- Added panic recovery with automatic 1-minute backoff restart to the inventory scheduler and
  executor, preventing a single job panic from cascading across cluster nodes (#2522)

### Multipart / Object Operations

- Fixed double XML response during `CompleteMultipartUpload` — when a precondition failure
  (`If-Match`/`If-None-Match`) occurs after the whitespace keep-alive goroutine has already
  written HTTP 200 and the `<?xml` header, the error was written a second time, producing
  malformed responses (#3134)
- Fixed `CancelBatchJob` deletion being overwritten by a concurrent final persist from the job
  executor (#3129)

### Scanner / Decommission

- Fixed data race on `ctx` variable in `nsScanner` goroutine — outer loop's `ctx` was mutated
  inside a spawned goroutine. Shadowed with `:=` to isolate scope (d5d90f17)
- Fixed decommission incorrectly migrating per-pool scanner internal files
  (`.usage-cache.bin`, `.background-heal.json`) — these are pool-specific and regenerated
  automatically (#3161)

### Logging / Observability

- Fixed `WaitGroup` data race in logger queue worker lifecycle — `workerWG.Add(1)` was called
  inside spawned goroutines, racing with `workerWG.Wait()` in `RemoveTarget` (20e26993)
- Fixed excessive logging on cordoned nodes — connection retries to outgoing nodes now respect
  context cancellation instead of producing immediate errors in a tight loop (#3036)
- Fixed `ClusterSummaryHandler` performing three independent cluster-wide `ServerInfo` RPC
  fan-outs; now reuses a single response, reducing redundant RPCs by ~67% (#3110)

### Metrics / Admin

- Fixed percent-encoded URL paths not decoded in the metrics v3 handler — wildcard characters
  sent as `%2A` by RFC 3986-compliant clients were not recognized (#3026)
- Fixed `ServicesQueryHandler` not including LDAP status — extracted `getServicesInfo` now
  populates `LDAPStatus` alongside other service health fields (#3092)

### Encryption / Batch

- Fixed incorrect `BucketKeyEnabled` reporting in batch-catalog for SSE-S3 and SSE-KMS objects
  (#3043)

### Quality of Service

- Fixed `ConcLimiter` spinning with an unnecessary `sleep` and a dead `maxDelay` code path
  (#3114)
- Fixed `qos.Error` missing `Unwrap()`, breaking standard error chain inspection (#3082)
- Fixed `joinErrs` iterating over an empty string slice instead of the actual errors slice (#3206)

### Storage

- Fixed tmpfile cleanup not running on error paths and scratch files not using the local drive,
  which could leave temporary data on wrong drives (#3086)

### Tier Validation

- Fixed tier validation returning inconsistent error codes — `BucketNotFound` and invalid
  credential errors now map to the correct S3 error codes (#3047)

---

## Improvements

- **Scanner advanced config** — revives `delay` and `max_wait` as hidden advanced configuration
  options that override the speed preset when explicitly set, enabling fine-grained scanner
  timing control (#3102)
- **Batch key rotation template** — adds `plaintextOnly` and `forceEncryptLocked` filter options
  to the key rotation job template (#3137)
- **Inspect output for `--config` mode** — `mc admin inspect` now includes a rewritten
  `config.yaml` with local drive paths and a `start-minio.sh` script when the server runs in
  `--config` mode (#3152)
- **Kubernetes diagnostics** — `mc support diag` now includes operator version, container images,
  and Helm chart versions in the diagnostics bundle (#3003)
- **Drive mount stability** — updated `madmin-go` adds the `FstabSource` field to the `Partition`
  struct, enabling detection of whether drives are mounted using stable UUIDs/LABELs or unstable
  device paths (#3063)
- **Audit log Parquet compatibility** — request JWT claims are converted to a string map in API
  audit logs, enabling Iceberg/Parquet-based audit log storage (#3180)
- **Notification listener** — the SSE endpoint now sends HTTP 200 immediately when listening
  starts (before the first event), improving compatibility with proxies and clients that buffer
  until a status line is received (#3155)
- **Tables: nested table prefixes** — tables now use a nested prefix layout for improved
  namespace isolation (#2976)
- **Tables: updated iceberg-go** — refreshed the iceberg-go dependency to pick up upstream
  fixes and improvements (#3181)
- **Console updated to v0.0.38** (#3071)

---

## Upgrade Instructions

For detailed upgrade instructions, please read: https://docs.min.io/enterprise/aistor-object-store/upgrade-aistor-server/

Platform-specific upgrade guides:

- **Linux/Bare Metal**: https://docs.min.io/enterprise/aistor-object-store/upgrade-aistor-server/upgrade-aistor-linux/
- **Kubernetes with Helm**: https://docs.min.io/enterprise/aistor-object-store/upgrade-aistor-server/upgrade-aistor-kubernetes-helm/

### New Configuration Options

- `MINIO_KUBERNETES_TOKEN_VALIDATION` — selects Kubernetes token validation mode: `oidc`
  (OIDC endpoint, no RBAC required) or `tokenreview` (existing Kubernetes API behavior)
- Scanner `delay` and `max_wait` — hidden advanced options that override the scanner speed preset

### Support

For enterprise support:

- SUBNET Support: https://subnet.min.io
- Documentation: https://docs.min.io
