The Azure SDK team is pleased to announce our September 2026 client library releases.

4 packages released this month.

Beta Packages (3)

  • AMQP

  • Azure Blob Storage Checkpoint Store

  • Event Hubs

Release highlights

AMQP 1.0.0-beta.13 Changelog

Features Added

  • The Rust AMQP backend now generates SAS tokens from a shared access key. It sends CBS put-token requests with the servicebus.windows.net:sastoken token type.
  • Added support for the AMQP Decimal types (AmqpDecimal128, AmqpDecimal64, and AmqpDecimal32).

Bugs Fixed

  • MessageSender now stores the negotiated maximum message size when its link attaches, and GetMaxMessageSize returns that stored value instead of reading the link. The value is fixed when the peer’s ATTACH arrives and cannot change for the life of a link, but the read failed once the link was no longer attached, so callers were discovering a dead link from an exception thrown by a getter. The value is read again on each attach, so an entity whose maximum was reconfigured between links stays correct. MessageSender::IsLinkDetached reports the same fact without throwing, and a close no longer waits for a DETACH from a peer that has already detached. The teardown still runs on every path. This change applies to the uAMQP transport. [#7389]
  • uAMQP pollable registration and removal no longer block each other while a poll is in flight. The polling registry now waits on completion notifications, and sender, receiver, and link setup and teardown do not hold connection locks across registry operations. The polling thread now sleeps when no pollable is registered. It spun on one core after a process closed its last connection. [#7370]
  • uAMQP now tears down unsettled sends without leaving late dispositions with freed callback state. Sender Open cleanup no longer deadlocks with link polling. Sender Open, sender Close, and receiver Close report caller cancellation separately from synthetic timeout. [#7350]
  • A close that fails now leaves the object closed. ManagementClient, MessageSender, and MessageReceiver kept the open flag when the close threw, and the destructor then stopped the process. [#7323]
  • The connection no longer returns a cached CBS token that is at or near its expiry. It authenticates the audience again instead. [#7254]
  • The connection now replaces each cached CBS token before that token expires, so a client that runs for longer than one token lifetime keeps working. This refresh applies to the uAMQP transport. Without this refresh, a send that gets the amqp:unauthorized-access condition stops at the first attempt, because the Event Hubs producer treats that condition as not transient. [#7254]
  • The token refresh thread now wakes when a caller authenticates a new audience. Before, its wait tested the stop flag alone, so it slept on a deadline that it computed before that audience existed, and it left the new token unexamined for up to one minute. A token with a lifetime shorter than that delay could expire before its first refresh. This change applies to the uAMQP transport. [#7254]
  • The management client now gets the current token for each operation and puts it in the security_token application property. Before, it sent the token that it got when it opened. A management client lives as long as the client that owns it, so that token expired while the client continued to send it. The service reads that property: an operation that carries a token that is not valid gets the amqp:not-allowed condition with status code 500, and Event Hubs does not count that condition as transient. This change applies to the uAMQP transport. [#7254]
  • An AMQP operation that the caller did not bound now gets a default deadline of 60 seconds, and a connection that goes to the error or the end state now wakes every operation that waits on it. A send on a connection that the service dropped waited forever on both transports: uAMQP stops the poll of the connection in those two states, and the Rust runtime blocks the calling thread with no bound. A receive keeps the deadline of the caller, because a receive is a long poll that the caller controls. The link attach and the link detach carry the same bound on both backends, because a rebuild runs both of them against the connection that died. The uAMQP sender attach also registers for the connection wake, so a connection that dies during a rebuild attach ends that wait. [#7254]
  • The Rust connection now marks itself closed before it calls the native close. A close that reached its new bound returned an error and threw with the open flag still set. The Event Hubs recover path catches that exception and then destroys the connection, and the destructor stopped the process because the flag stayed set. ManagementClient, MessageSender, and MessageReceiver already follow this rule. [#7254]
  • Each uAMQP send now owns its completion state. A send that reached its deadline left the uAMQP operation in flight, because a cancel can make uAMQP call the completion handler two times. That operation later pushed its result into the one queue that the sender shared between every send, so the next send took the stale result as its own. A retry could thus report the outcome of the attempt before it. [#7254]
  • The uAMQP receiver now registers its connection waiter under the connection lock. That waiter reads the saved error of the link on the calling thread, while the polling thread writes the same field, so the read was a data race. The sender already used this lock. [#7254]
  • A cancelled caller no longer stops a teardown on the Rust transport. A close took the time that remained for the caller as its bound. A cancelled context leaves no time, so the bound was zero and every close failed at once with an Elapsed error. The caller then stopped before it closed the connection, and the destructor of that connection stopped the process. A teardown now takes the default bound when the deadline of the caller already passed. It keeps a caller deadline that has time left. [#7254]
  • The uAMQP sender now holds every send that waits, not one send at a time. ProducerClient::Send lets sends to one partition run together, so a second send replaced the first in the old single slot. uAMQP drains each in-flight send before it reports the error state, so no send was stranded in practice. This change keeps the error wake correct if that order changes. [#7254]
  • ServiceBusSasConnectionStringCredential no longer throws when the connection string EntityPath and the entity path argument differ only by ASCII letter case. The comparison folds ASCII A-Z only. It is not the culture-aware InvariantCultureIgnoreCase comparison that .NET uses. GetEntityPath() returns the connection string spelling. .NET returns the explicit argument instead, so this behavior deviates from .NET. [#7261]
  • A claims based security open that fails now names the result, the audience, and the function that asked for the token. The exception said “Could not open Claims Based Security object.” and nothing more, so a reader could not tell which audience failed or whether the failure came from the first authentication or from the token refresh. The connection also writes a warning that adds the token type and the token expiry. Neither the exception nor the warning holds the token.
  • The claims based security warning also names the connection instance, the host, the connection state, and the time that the open took. A reader can now separate a client fault from a service fault: an open that fails in about no time, on a connection that is already in the End state, never reached the service, and a repeated instance number shows that the client did not build a new connection. The connection state is now atomic, because the uAMQP polling thread writes it while another thread reads it for this line.
  • The uAMQP connection now names the reason that the service gives when it closes the connection. uAMQP reads that reason from the close performative and offers it through one subscription, and the connection did not take that subscription, so the reason reached no log. A client that the service closed after an idle period saw only the failures that followed. A transport I/O error now writes a separate warning with the connection instance, host, and state. The uAMQP callback provides no error payload, so the warning says that no details are available.
  • The uAMQP message sender and message receiver now write the detach condition and the description each time the service detaches a link, and the line no longer needs the AMQP trace option. Each one also writes the line for a detach that arrives during the open. Before, that detach was silent, and the open reported a generic error that did not name the condition. The $cbs links take that path when the service rejects the attach.
  • A claims based security open that fails now throws CbsOpenFailedException, which carries the CbsOpenResult. The three failures need different handling: Error reached the transport and may be retried, while Cancelled is the caller’s own cancellation or deadline and Invalid is a state error. The result was previously readable only by matching the message text, so a reword would have changed caller behavior with no compiler error. The type derives from std::runtime_error and carries the same message, so existing handlers keep working. The Rust backend reports every open failure by throwing rather than by returning a result, so those throws are classified at the shared call site and carry the same type.
  • The uAMQP management client now closes the message sender when the message receiver fails to open. Two handlers returned a status without that close, and a message sender that stays open stops the process in its own destructor.
  • The uAMQP management client now names the management node and the open status in the lines that it writes when an open fails, and it keeps the text of the exception that ended the open. The message sender open failure moved from the Error level to the Warning level, because that call reports the failure to its caller.
  • A claims based security open that fails now carries the reason that the layer below reported. CbsOpenResult::Error covers every transport, TLS and link failure, so a reader holding only the result could not separate a refused socket from a rejected attach. The management client wrote that reason to the log and then dropped it, because ManagementClientImpl::Open reports a failure as a status and the exception that named the cause was destroyed in the handler. The reason now travels with the status and reaches both the warning and the CbsOpenFailedException message, so a caller that logs the exception and has no log listener can still tell what failed. It names which of the two links failed, because the sender and the receiver fail for different causes. The reason is empty when the layer below gave none, and the sentence then reads exactly as it did before. It never holds the token.
  • The claims based security object now keeps the AMQP error that the service sent. ClaimsBasedSecurityImpl::OnError receives the condition, the description, and the info map, which is the richest statement the service makes about a refused claim, and it only wrote them to the log. They are now added to the reason that the open failure carries. The capture takes a lock of its own, because that callback runs on the polling thread while the management client holds its open lock.

Azure Blob Storage Checkpoint Store 1.0.0-beta.4 Changelog

Other Changes

  • No public changes in this release.

Event Hubs 1.0.0-beta.14 Changelog

Features Added

  • [#7250] Restored connection-string authentication for ProducerClient and ConsumerClient, including support for the Event Hubs emulator.
  • [#7295] Connection-string authentication now works on the Rust AMQP backend. ProducerClient and ConsumerClient no longer throw when the caller passes a connection string.
  • [#7254] ProducerClient::Send now builds a new sender on each retry attempt. A failed attempt discards the sender, the session, and the connection for that partition, so the next attempt builds all three again and authenticates with a current token. A send that a link detach ended previously failed for the life of the client.
  • [#7254] PartitionClient::ReceiveEvents now attaches a new receiver after a link fault, and it starts after the last event that it gave the caller. So the caller sees no duplicate event and no lost event. A permanent condition, for example amqp:link:stolen, still reaches the caller at once. A call that already holds events gives them back and recovers on the next call.

Bugs Fixed

  • [#7254] A teardown of the cached sender no longer runs while another thread sends on that sender. ProducerClient::Send gives each attempt a copy of the sender, and a failed attempt on one thread closed the object that a second thread was using. On the Rust AMQP backend that close frees the sender, so the race was a use after free. Each partition now has a guard that lets sends run at the same time and makes a teardown wait for the sends in flight. ProducerClient::Close uses the same guard, and it now logs a failed close and continues instead of leaving the other objects open.
  • [#7254] ProducerClient::CreateBatch now builds a new sender when it cannot read the maximum message size. The client caches a sender for each partition, and a cached sender holds a link that the service detaches after 30 idle minutes. The size of a batch comes from the attached link, so this call was the first one to touch the dead link, and it threw. The Send(EventData) overloads go through this call, so the whole producer failed after an idle period even though Send builds a new sender on each attempt.
  • [#7254] Updated producer retries to honor EventHubsException::IsTransient, treat empty AMQP error conditions as transient, stop immediately for unknown and known non-transient failures, preserve bounded retries for AMQP runtime failures, and make backoff cancellable through Azure::Core::Context. Retry accounting now always performs the initial attempt and treats MaxRetries as additional retry attempts.
  • [#7335] The internal properties client can no longer end the process through its destructor. EventHubsPropertiesClient::Close marked the client closed only after ManagementClient::Close returned, so a close that threw left the client marked open, and it also skipped the session end. The destructor then closed the same client a second time with no try block, and a destructor is noexcept, so that second throw would call std::terminate. Close now marks the client closed before the call, gives each step its own try block, and ends the session on the failing path too. The destructor catches and logs. This is a guard against a throwing close, and not a fix for an observed crash: a live test that left a management link idle for 35 minutes did not make the uAMQP close throw. Release 1.0.0-beta.11 records the same rule in [#6957].
  • [#7257] Fixed the partition key on a batch envelope. EventDataBatch::ToAmqpMessage wrote the x-opt-partition-key value to the AMQP delivery-annotations section. The Event Hubs service ignores that section. The batch also built the envelope from the message before the code applied the partition key annotation. A batch with a partition key thus spread across all partitions. The partition key now goes in the message-annotations section, on the batch envelope and on each message in the batch. A batch that sets EventDataBatchOptions::PartitionKey now lands on one partition.
  • [#7254] ProducerClient::Send no longer waits forever when the connection goes away. A caller that gives no deadline now gets a bound of 60 seconds on the send, and the client treats that timeout as transient, so the next attempt builds a new sender. A close of the sender or of the receiver also comes back when the connection is gone, instead of waiting for a detach that never arrives, and the attach that a rebuild runs next carries the same bound. PartitionClient::ReceiveEvents keeps the deadline of the caller, because a receive is a long poll that the caller controls.
  • [#7254] Processor::Close and ConsumerClient::Close now finish closing every partition after one AMQP teardown reports a lost connection. A receiver detach can report IllegalSessionState after the service resets its connection. That error stopped the cleanup loops, left other connections open, and could end the process when those open connections were destroyed.

Event Hubs 1.0.0-beta.15 Changelog

Bugs Fixed

  • [#7389] ProducerClient now tests a cached sender for liveness before it uses one. Holding a sender in the map is not the same as holding a usable one: a link that the service detached during an idle period stayed cached, and the read of the maximum message size in CreateBatch was the first call to touch it, so that read threw and the exception was how the client learned the link had died. The producer now discards a detached stack before use, and the size read no longer depends on a live link. A rebuild after an idle close costs the same connection, TLS and claims based security handshake as before; what this removes is the exception and its warnings on that path. This change applies to the uAMQP transport.
  • [#7389] The claims based security retry in ProducerClient::CreateBatch now waits a short random interval before its one further attempt, instead of making it in the same instant. Every producer in a process that failed together went back into whatever caused the first failure together. The wait is a uniform value between zero and 100 milliseconds, drawn from a generator seeded for each thread. It is deliberately not the configured RetryDelay and not a backoff step: the purpose is to spread producers that failed at the same moment, not to wait for a condition to clear, so it does not add the best part of a second to a path that is already rebuilding a connection, and it does not depend on RetryOptions. The bound stays one retry, and only a claims based security open that reported CbsOpenResult::Error is retried; Cancelled and Invalid still reach the caller on the first attempt.

Latest Releases

View all the latest versions of C++ packages here.

Installation Instructions

To install the packages, copy and paste the following commands into a terminal:

$> vcpkg add port azure-core-amqp-cpp
$> vcpkg add port azure-messaging-eventhubs-cpp
$> vcpkg add port azure-messaging-eventhubs-checkpointstore-blob-cpp

You can also install the packages from source:

# From Source
git clone https://github.com/Azure/azure-sdk-for-cpp
# git checkout <tag_name>
# For example:
git checkout azure-storage-blobs_12.0.0

Feedback

If you have a bug or feature request for one of the libraries, please post an issue to GitHub.