opensearch-go v5.0.0
CRITICAL UPGRADE RELEASE NOTE - v5 is NOT a drop-in replacement for v4.
Two runtime defaults flip in v5, so code that compiles and passes against v4 can behave differently against v5 without a single line changing. Read this before you upgrade.
- Partial failures are now returned as errors. Bulk item failures, shard failures, and unconfirmed replica writes -- which v4 reported only inside the response body -- come back as typed Go
errorvalues by default (Config.Errors == nilnow meanserrmask.Empty). Restore v4 behavior withErrors: errmask.New(errmask.All)orOPENSEARCH_GO_ERROR_MASK=all.- The router is on by default. The client injects the default router and enables on-start node discovery unless
OPENSEARCH_GO_ROUTER=false. In v4 this was opt-in.Beyond the defaults, the module path changes to
/v5, theopensearchapipackage is now spec-generated (its Req/Resp/Params types are fully typed), thesigner/aws(AWS SDK v1) package is removed, and several config fields and helpers are gone. The full field-level migration is inUPGRADING_V5.mdandopensearchapi/UPGRADING_V4_TO_V5.md.
v5.0.0 is the first stable release of the v5 line. It ships the three themes the v4.7.x line previewed -- a partial-failure error model, a rewritten transport, and a topology-aware routing layer -- now as defaults, on top of an opensearchapi package generated in full from the OpenSearch API specification. The v4 line remains supported for callers who are not ready to move.
Requires Go 1.26 or later.
Full Changelog: v4.7.3...v5.0.0
1. Breaking changes in v5.0.0
Most surface at compile time. The upgrade guide has the complete list with before/after for each; these are the ones most likely to touch your code:
- Module path is
github.com/opensearch-project/opensearch-go/v5. Update your imports from/v4to/v5; the in-sourceopensearchapi.Xqualifier is unchanged. - Nested modules moved the major-version suffix to the end of the path, so
.../opensearch-go/v5/ospromis now.../opensearch-go/osprom/v5(and likewiseosotel,log-slog,log-zerolog,cmd/osgen,cmd/osapilint). If you carried areplacedirective to build these, delete it (#1115). opensearchapiis now the code-generated package, replacing the hand-written v4 one (previewed in v4 atv5preview/opensearchapi/). Field-level deltas (DocumentID->ID, optionalParamsbecoming*Params, shared params moving into embeddedTimeoutParams/DebugParams,BulkResp.Itemsbecoming[]BulkItem) are inopensearchapi/UPGRADING_V4_TO_V5.md(#650).signer/awsis removed. Usesigner/awsv2, which mirrors AWS's own SDK-version naming. For callers on v4 this is a full AWS SDK v1 -> v2 signer migration (session.Options->aws.Config, and theOpenSearchService/OpenSearchServerlessconstants become the"es"/"aoss"literals).opensearchtransport.DebuggingLoggerandLoadDebugLogger()are removed, replaced by the newdebuglogpackage. SetConfig.DebugLogger(orOPENSEARCH_GO_LOG=debug) instead; adapters ship as thelog-zerologandlog-slogmodules (#828).opensearchtransport.Clientis renamed toopensearchtransport.Transport(#853).EnableMetrics,IncludeDedicatedClusterManagers, andopensearch.ToPointerare removed. Per-request metrics are now always collected lock-free andMetrics()returns the full snapshot unconditionally; dedicated cluster managers are unconditionally excluded from request routing; replaceToPointer(v)with your ownptrhelper or the nativenew(value)form (#892, #1004, #871).Performis removed from bothopensearch.Clientandopensearchtransport.Transport;Streamis now the sole method onopensearchtransport.Interface. Custom transports must implementStream(#872).- Numeric query parameters are typed to match the spec:
versionparams become*intsoversion=0reaches the wire, and OpenAPInumberparams (min_score,requests_per_second, ...) becomefloat64/*float64(#1148, #1104). - Generated identifiers now follow Go initialism convention (
IsmPolicy->ISMPolicy,NodesInfoNode.Os->OS, and many more); JSON wire tags are unchanged (#863). - The search response envelope is reshaped:
resp.Hitsis nowSearchHitsMetadataandresp.Hits.Hitsis[]SearchHit, so_id,_score,_seq_no/_primary_term, and thesortcursor are reachable from a typed response for the first time. Access throughresp.Hits.Hits[...]is unchanged.
2. Error handling (on by default in v5)
Partial failures that OpenSearch reports under an HTTP 200 -- failed bulk items, failed shards, unconfirmed replica writes -- are surfaced as typed Go errors:
| Error type | Returned by |
|---|---|
*PartialBulkError
| Bulk
|
*PartialSearchError
| Search, MSearch, MSearchTemplate, SearchTemplate, Scroll.Get
|
*ShardFailureError
| Index, Doc.Create, Doc.Delete, Update
|
*MultiSearchItemError
| MSearch, MSearchTemplate (per sub-response)
|
Which categories are reported is a per-category mask on Config.Errors, overridable at runtime with OPENSEARCH_GO_ERROR_MASK. The recommended call-site pattern is a for/switch over opensearchapi.Errors(err), which flattens single- and multi-wrapper error shapes into one slice; on a partial failure the response is still fully populated alongside the error. Helpers IsPartialFailure, ToleratePartialFailures, and RequireSuccessRate support threshold-based tolerance. See guides/usage-error_handling.md (#816).
3. Routing (on by default in v5)
The client now chooses a node per request from cluster topology and load rather than plain round-robin, and auto-discovers nodes on start. OPENSEARCH_GO_ROUTER=false restores round-robin.
- Role-aware: bulk/reindex/streaming route to ingest nodes; searches, mget, scroll, PIT, and field-caps to search/data nodes; writes and shard maintenance to data nodes. Dedicated cluster managers are excluded from request routing.
- Shard-aware: client-side murmur3 hashing mirrors OpenSearch shard routing so
?routing=and document-ID requests reach a node hosting the target shard, with rendezvous-hashing fallback. - Congestion-aware: per-pool AIMD congestion windows, RTT bucketing that prefers AZ-local nodes and overflows under load, and thread-pool stats polling that demotes and recovers overloaded nodes.
- Adaptive
max_concurrent_shard_requestsderived from a cluster-wide congestion signal, clamped to a[floor, cap]range, never applied over an explicit caller value. - Seed-URL fallback when all router pools are exhausted, triggering rediscovery. Disable with
OPENSEARCH_GO_FALLBACK=false.
On a secured cluster the router's probes need read-only monitoring privileges (cluster:monitor/nodes, cluster:monitor/health); without them the client degrades gracefully to GET / and seed URLs rather than erroring. Full reference in guides/transport-routing.md and guides/config-envvars.md (#786, #816).
4. Generated API (opensearchapi)
The opensearchapi/ package is produced by cmd/osgen from the OpenAPI spec: consistent Req/Resp/Params triples, sub-clients mirroring OpenSearch namespaces (client.Cat, client.Cluster, client.Indices, ...), and a plugins/ subtree for ML, k-NN, security, ISM, and the rest.
- Typed path builders in
internal/path/reject empty required segments, fixing a class of double-slash URL bugs across 74 request methods. - Enum-like
oneOf-of-const schemas emit named Go string types with one exported const per value (e.g.NodeRole), and int-backed enums emit closed-set types with a typed unknown-value error. - The generator honors the OpenAPI
discriminatorand typed unions (CommonMappingProperty, the analysis unions,ClusterRemoteInfoCluster) so 146 subtypes decode by the property the payload names rather than a token-class guess. - Union branch accessors return
(T, error)instead of a silent zero value when the union holds a different branch (opensearchapi.UnionBranchError). - Backward-compatibility forwarders keep top-level
client.Bulk/MGet/Updateand theclient.Document/client.PointInTime/client.Indicesfield aliases working during migration.
5. Transport, connection lifecycle, and observability
Client.Close()onopensearch.Clientandopensearchapi.Clientreleases discovery, health/stats polling, and DNS-refresh goroutines along with idle connections. Implicitly-created default clients are cached and shared by config hash, tunable withOPENSEARCH_GO_DEFAULT_CLIENT_TTL(#893).- Native API-key auth via
APIKeyonopensearch.Config(sendsAuthorization: ApiKey <key>) (#907). - Client-side DNS caching, on by default, with last-known-good fallback through transient resolver outages.
InsecureSkipVerifydisables TLS verification without a customhttp.Transport, keeping pooling, HTTP/2, and timeout defaults.Stream()for raw byte forwarding and per-attemptRequestTimeoutto bound stalled round-trips.- Lock-free metrics and an enriched observer surface:
RequestEventgainsRouteName/Index/PoolName, response and stream events fire per request, and theospromandosotelmodules provide Prometheus and OpenTelemetry metric bundles off the core dependency graph. - Data-race and correctness fixes on the retry path (request mutation across attempts, HTTP/2 connection reuse after timeout, base-path stacking on retries) and HTTP/2 repair when
CACert/InsecureSkipVerifyis set on a caller-supplied transport (#1121, #1089, #1162).
6. Bulk indexer
Flush(context.Context) erroron theopensearchutil.BulkIndexerinterface drains the queue on demand and leaves the indexer open. Types implementing the interface must add the method (#336).- Per-document ordering: every action on one document routes to a fixed worker so a create and a follow-up update flush in order (#464).
- Correctness fixes:
_id/routingvalues are no longer HTML-escaped before transmission (a data-corruption bug present since 2021), mixed bulk batches route per-item rejections correctly toOnError/OnFailure, and peak batch memory is released after a traffic burst subsides (#824, #1106, #912).
7. Tooling
cmd/osgengenerates theopensearchapipackage and typed path builders from the spec, with checked-in allowlists guardingjson.RawMessageand duplicate-JSON-tag shadowing so a generator regression fails generation rather than silently widening the raw-JSON surface.cmd/osapilintmigrates a Go module across major versions:rewriteapplies syntactic API-shape changes before the code compiles against the target, andvet -fixcatches runtime type-assertion hazards. Ships the v2 -> v3, v3 -> v4, and v4 -> v5 hops, chainable to migrate v2 -> v5 (#933, #951).
Dependencies
- Bump
golangci-lintv2.11.2 -> v2.11.4. - Bump
github.com/aws/aws-sdk-go-v2v1.41.1 -> v1.41.7,.../config-> v1.32.17,.../credentials-> v1.19.16, andgithub.com/aws/smithy-gov1.24.0 -> v1.25.1 (#831). - Bump
golang.org/x/syncv0.19.0 -> v0.20.0,golang.org/x/modv0.33.0 -> v0.35.0, andgithub.com/wI2L/jsondiffv0.7.0 -> v0.7.1 (#831).
Upgrade guides and documentation
UPGRADING.md- version-history index across every major versionUPGRADING_V5.md- v4 -> v5 migration, with before/after for each breaking changeopensearchapi/UPGRADING_V4_TO_V5.md- field-level delta for the generated API package, including the union rename tableguides/README.md- index of all guides, grouped by subsystemguides/usage-error_handling.md- partial-failure errors and the error-mask referenceguides/transport-routing.md- routing architecture, connection scoring, pool lifecycle, and cost modelguides/transport-node_discovery_and_roles.md- node discovery and role-based selectionguides/transport-cluster_health_checking.md- health-check capability detection and thecluster:monitorpermissions the router needs on a secured clusterguides/transport-metrics.md- client-side metrics and connection/policy/router snapshotsguides/transport-observer_metrics.md- the observer event sink behind theospromandosotelmodulesguides/config-envvars.md- canonical reference for everyOPENSEARCH_GO_*environment variableUSER_GUIDE.md- general usage and AWS signer setupCHANGELOG.md- the complete, unabridged list of changes in this release
Contributors
Thanks to everyone who contributed to this release: @ryanyuan, @sean-, @iprithv, @magic-peach, @Ashwinnbr007, @peterzhuamazon, @Hailong-am, @iamrajiv, @Jakob3xD, @jeffmclean-cs, @LeeFred3042U, @MohammedAlkindi, @molloyzak13, @sooncj, @typhon8, @venkateshwaracholan, and @yanaix10.