Skip to content

October 2026

The changes in the October 2026 releases that ask something of your project, newest first. See the October 2026 highlights for everything else that changed. Each one names the first version of each package that has it: you need the change only when you move from below that version to it or above. Each one is the change since the September 2026 release, as it stood at the end of October.

A Storyblok catalog page’s category is a text field

Section titled “A Storyblok catalog page’s category is a text field”

In: storyblok 0.9.0

catalog_page.category holds the category id as text instead of using the commercetools category picker plugin, and local.storyblok_category_field_options is no longer used. Remove that local from your Terraform and apply it. Pages the picker wrote keep working.

The generated Terraform adds block_variables.tf with sku_pattern and category_id_pattern, which check the format of a key field. Both default to ^\S+$; set them in your tfvars to match your commerce backend.

A hero or page title says whether it is the page heading

Section titled “A hero or page title says whether it is the page heading”

In: contentful 0.9.0, payload 0.5.0, schemas 0.19.0, storyblok 0.8.0

HeroBlock.isPageHeading and PageTitle.isPageHeading are new non-null fields. A block mapper of your own that returns a HeroBlock or a PageTitle must set isPageHeading: false; the page mapper marks the one block that is the page’s heading.

In the storefront, render the title of the block with isPageHeading as the h1. When no block has it, render the page’s new heading field as the h1.

In: contentful 0.9.0, payload 0.5.0, schemas 0.19.0, storyblok 0.8.0

Content pages and catalog pages carry seoTitle, seoDescription and seoImage, mapped onto meta. There is no migration: apply the updated content model, then fill the new fields.

CMS Removed
Storyblok The seo field with the seo-metatags plugin on content_page and catalog_page
Contentful The pageMeta content type and the meta link on pageContent
Payload The meta group on pages and catalog-pages

PageMeta.keywords is deprecated, since no CMS stores keywords any more.

In: contentful 0.9.0, payload 0.5.0, schemas 0.19.0, storyblok 0.8.0

The Page union is now an interface that every page type implements, with the new ArticlePage and ArticleOverviewPage. A selection of ... on ContentPage under page keeps working. AbstractPage is deprecated: rename a fragment on AbstractPage to on Page.

  • In the CMS contract, ProductCategory is keyed by key alone and its id is @external. A supergraph that composes a CMS subgraph without a commerce subgraph serving ProductCategory no longer resolves a category’s id.
  • Apply the new content types: the Contentful and Storyblok Terraform, or a Payload migration for the article-pages and article-overview-pages collections.

In: contentful 0.9.0, payload 0.5.0, schemas 0.19.0, storyblok 0.8.0

NavigationMenuItem.iconName replaces the uploaded icon image, which is deprecated. The generated Terraform reads the icon names from a local that your project defines:

CMS What to add
Storyblok local.storyblok_menu_icon_options, a list of { name, value }
Contentful local.contentful_menu_icon_names, a list of names
Payload Optional: menuIcons: [{ label, value }] on evolveCms(), and a migration for the field

Define the local before you apply the generated Terraform.

In: payload 0.5.0

Unpublished pages, catalog pages, snippets and site chrome were readable without signing in, on the storefront and through the admin app’s API. Every collection with drafts now gives an anonymous caller published documents only. A document created through the Local API without _status: "published", such as one from a seed or an import, is a draft and no longer appears on the storefront. Publish it.

Content-modified events carry changes, and paths is optional

Section titled “Content-modified events carry changes, and paths is optional”

In: schemas 0.19.0

A content-modified event names each change in a changes list, the same way for every CMS: contentType, the bare path, the store locale and an optional storeKey. paths and contentType at the top level are deprecated, and paths is no longer required. Payload sends only changes. A consumer typed against the generated schema must handle an event without paths: read changes where it is present.

A cart becomes an order once its payments cover it

Section titled “A cart becomes an order once its payments cover it”

In: commercetools 0.22.0

A cart can carry several payments, such as a gift card and a card payment for the rest. A cart no longer becomes an order on the first reported payment, but once what its payments have secured reaches the gross total. Until then the cart stays open to changes.

A payment adapter that relied on an order existing after any reported payment, a failed one included, must read Cart.amountToPay or the PaymentComplete.order field, which stays empty while a payment covers only part. A failed payment on a cart without an order releases the cart again.

A line that cannot be added is reported in lineResults

Section titled “A line that cannot be added is reported in lineResults”

In: commercetools 0.22.0, schemas 0.19.0

cartLineItemsAdd adds the lines it can and reports every requested line in lineResults, as added or failed with a reason. A line that cannot be added, also when it is the only one, no longer comes back in cartErrors. Read lineResults for an out-of-stock add. cartErrors remains for a request that fails as a whole, such as a missing cart or a version conflict.

In: commercetools 0.22.0, commercetools-adyen 0.6.0, medusa 0.10.0, schemas 0.19.0

Code that switches over these exhaustively must handle the new members:

Type New members
ProductAvailabilityType NOT_FOR_SALE
CartErrorCodeType NOT_FOR_SALE, MERGE_NOT_UNDOABLE
QuoteStatusType RENEGOTIATION_REQUESTED
BusinessUnitCapabilityType REQUEST_RETURNS
PaymentNext PaymentSdkAction, PaymentPending
PaymentErrorCodeType PAYMENT_REFUSED, UPDATE_NOT_SUPPORTED
  • A variant without a price in the shopper’s currency reads NOT_FOR_SALE where it used to read IN_STOCK. On Medusa, a variant that is out of stock but takes backorders now reads BACKORDER.
  • A quote the buyer replied to reads RENEGOTIATION_REQUESTED instead of DECLINED. On commercetools, a pending quote past validUntil now reads EXPIRED.
  • Adyen answers every action that is not a redirect with PaymentSdkAction. It used to report a PayPal payment as complete.

An approval’s order, approver and rejecter can be null

Section titled “An approval’s order, approver and rejecter can be null”

In: commercetools 0.22.0, medusa 0.10.0, schemas 0.19.0

OrderApproval.order is null when the order was deleted, and on Medusa until the order is created, once every signature is in. Show such an approval from its status, dates and requester. On commercetools, approving one answers ORDER_NOT_FOUND; rejecting it still works.

OrderApprovalDecision.approver and OrderApprovalRejection.rejecter are null where the merchant decided rather than an associate of the business unit.

applyReverseCharge is replaced by applyVatRules

Section titled “applyReverseCharge is replaced by applyVatRules”

In: commercetools 0.22.0, schemas 0.19.0

The cart follows the standard EU and B2B VAT rules. Reverse charge is decided by the delivery country and a verified VAT number, or for a business unit by the company’s VAT registrations, and no longer by the billing country.

applyReverseCharge({
applyVatRules({
sellerCountry: "NL",
taxCategoryKey: "zero-rate",
slug: "vat-shifting",
name: { en: "VAT reverse-charged" },
reverseChargeLine: {
slug: "vat-shifting",
name: { en: "VAT reverse-charged" },
},
exportLine: {
slug: "vat-exemption",
name: { en: "Export, 0% VAT" },
},
});
  • applyVatRules reads the cart’s business unit, so register it through new ApiExtensionModule({ clientFactory, extensions }) instead of createFastifyHandler(extensions).
  • Add the String fields vatNumberStatus and vatReason to the cart and order custom type you give CartModule, and eoriNumber before a business unit gets an EORI number.
  • Give CartModule a vatNumberCheck, such as ViesClient.check from @evolve-framework/vies. Without it a VAT number on a cart stays unverified and the cart is not reverse-charged.
  • A cart is no longer reverse-charged for being billed elsewhere in the EU. A consumer’s or guest’s cart needs a verified VAT number with its country prefix, recorded with cartSetVatNumber. A business unit’s cart follows the company’s registrations: the vatNumber field and the new vatNumbers Set of String field on your business unit type.

In: commercetools 0.22.0

toDiscountCodes(codes, cart.discountOnTotalPrice);
toDiscountCodes(codes, cart);

Cart.discountCodes and Order.discountCodes now also list a code whose cart discount targets line items or shipping, and a code’s amount is the total it takes off.

In: commercetools 0.22.0, medusa 0.10.0, schemas 0.19.0

A cart untouched for 60 days reads as ARCHIVED, unless it is the caller’s current cart, and BusinessUnit.carts leaves it out unless status asks for it. To show every cart, pass status: [ACTIVE, ARCHIVED]. On commercetools, keep archiveCartsAfterDays below the project’s deleteDaysAfterLastModification.

The price facet is in minor units with every engine

Section titled “The price facet is in minor units with every engine”

In: medusa 0.10.0, search-algolia 0.3.0

The Algolia and Medusa search adapters report a price range, and expect its filter bounds, in minor units such as cents, as commercetools and Meilisearch already did. If you call either adapter directly, read and send price ranges in minor units. A storefront that already divides the price facet by 100 needs no change. RangeFacet.currency names the currency where a range is money.

Medusa also indexed startingPrice 100 times too low: reindex after you upgrade.

Medusa lists automatic promotions apart from discount codes

Section titled “Medusa lists automatic promotions apart from discount codes”

In: medusa 0.10.0

An automatic promotion is listed under the new Cart.automaticDiscounts instead of under discountCodes. A storefront that showed automatic promotions among the codes finds them there.

Medusa needs core 1.8.0 and the fulfillment fields

Section titled “Medusa needs core 1.8.0 and the fulfillment fields”

In: medusa 0.10.0

Upgrade @evolve-framework/core to 1.8.0 or later. For Order.deliveries, let the Medusa application return fulfillments.items and fulfillments.labels on /store/orders and /store/orders/:id; the package README shows the middleware. Without them, deliveries come back with no items and no tracking.

Modules close in reverse composition order

Section titled “Modules close in reverse composition order”

In: core 1.10.0

CompositeModule.close() closes a module before the modules composed ahead of it, instead of after. Check any module whose close() relied on running before the modules composed after it. Every module is now closed even when another fails; several failures reject with an AggregateError.

In: persisted-documents 0.4.0

documentId derives the bare hex digest, without the sha256: prefix, which Hive usage reporting accepts. The ids must match what codegen publishes, so take this version together with the shared codegen config. In the client preset, keep your other options:

import { persistedDocuments } from "@evolve-storefront/persisted-documents";
presetConfig: {
persistedDocuments: { … },
persistedDocuments,
},

Regenerate and publish the document manifest with the app release. Without the shared config, the ids do not match the manifest, and a trusted-document router rejects the requests. An app that wraps documentId to strip the : can drop the wrapper. This replaces the sha256: ids of the September release.

In: feature-quote 0.17.0

useQuotes sends sort and status, and an older gateway rejects the whole query, so upgrade the framework first. The server puts orderable quotes first, each group newest first. QuoteStatus gains RENEGOTIATION_REQUESTED.

In: feature-organization 0.11.0

InviteAssociateFormInput is { email, roleIds } instead of { email, roleId }. If your onValidSubmit wrapped the role as [roleId], pass roleIds straight through. InviteAssociateDialog already does.

In: feature-shopping-list 0.8.0

The Money type had currencyCode, which matches nothing the schema sends. Rename it to currency wherever you use the type.

A net cart summary ends with the gross total

Section titled “A net cart summary ends with the gross total”

In: feature-cart 1.0.0

CartSummary with vatDisplay="net" leads with prices excluding VAT and ends with what is paid: “Total excl. VAT”, the VAT per rate, then “Total incl. VAT”. The bold total is now the gross amount. If you showed the net total as the amount to pay, read the “Total excl. VAT” row instead.

The checkout is rebuilt as a shell of sections

Section titled “The checkout is rebuilt as a shell of sections”

In: feature-cart 1.0.0, feature-quote 0.17.0

Nothing of the old checkout remains: no aliases and no deprecated exports. Recompose the checkout page as Checkout with CheckoutMain and one CheckoutSection per section, each ending in CheckoutSectionContinue, with CheckoutPlaceOrder in the last one. Checkout takes the cart and your section set: { id, title, isComplete, confirmOnArrival?, fingerprint? }[]. Write the cart from each onContinue with the mutations in ./hooks, which are unchanged. The feature-cart README has a “Checkout” section.

The cart documents select fields that are new in the October framework release, such as vatOutcome, amountToPay, and a line’s addOns, and an older gateway rejects the whole cart query. Upgrade the framework first.

Removed:

  • The subpaths ./checkout-context, ./checkout-sections, and ./checkout-call-to-action. ./schemas holds CheckoutDetailsSchema instead of CheckoutContactSchema and CheckoutSignInSchema.
  • The section and outcome model, such as defineCheckoutSection, resolveSections, and defineCheckoutOutcome, and the shipped sections, such as contactSection and defaultCheckoutSections.
  • CheckoutContextProvider, useCheckout, useCheckoutSection, and useCheckoutCallToAction.
  • The old parts, such as CheckoutAddress, CheckoutContactForm, and CheckoutDeliveryMethods.
  • The Cart.checkout messages, replaced by the Checkout namespace.

A quote request ends the checkout through useQuoteRequestEnding from feature-quote. Put its result in the endings of CheckoutFinishSection. It replaces quoteRequestOutcome, useQuoteRequestOutcome, useQuoteRequestConclusion, and QUOTE_REQUEST_OUTCOME_ID; use QUOTE_REQUEST_ENDING_ID for the id.

A credit note lowers the amount due on its invoice

Section titled “A credit note lowers the amount due on its invoice”

In: commercetools 0.21.0

An invoice’s amount due is its total less what was paid and what was credited. A finance sync that raises a credit note must also add the credit to the invoice it corrects: a successful Refund transaction for the credited amount, whose interactionId names the credit note. Then write the invoice’s status again. A credit note raised before this change leaves its invoice open until that refund is added.

A business unit’s cart keeps the buyer’s email

Section titled “A business unit’s cart keeps the buyer’s email”

In: commercetools 0.21.0

A cart created in a business unit keeps the buyer’s email as customerEmail instead of the unit’s contactEmail. A B2B service that sends order confirmations to order.customerEmail now mails the buyer. To copy the company’s contact as well, address the notification with orderConfirmationAddressees(order, businessUnit), which answers the recipient and the cc.

UserNotificationClient gains quote and back-in-stock methods

Section titled “UserNotificationClient gains quote and back-in-stock methods”

In: commercetools 0.21.0, schemas 0.18.0, user-notifications 0.6.0

Method Notification type In
quoteRequested quote-requested user-notifications 0.6.0
quoteReady quote-ready user-notifications 0.6.0
backInStock back-in-stock user-notifications 0.7.0
backInStockSubscribed (optional) back-in-stock-subscribed user-notifications 0.7.0
  • A class that implements UserNotificationClient must add the required methods.
  • Code that switches over UserNotification["type"] must handle the new types. Without a template for one, that mail is not sent.

Test-support cleanup leaves quote requests alone unless asked

Section titled “Test-support cleanup leaves quote requests alone unless asked”

In: commercetools 0.21.0

A project that uses quotes must pass quotes: true to commercetoolsTestSupport, and --quotes to evolve cleanup sweep, or quote requests are left behind. Without it, cleanup needs no view_quote_requests scope.

CartSummary states the VAT a gross total contains

Section titled “CartSummary states the VAT a gross total contains”

In: feature-cart 0.14.0

CartSummary shows one “Of which €x VAT (21%)” line per rate under a gross total. If you render such a line yourself as its children, it shows twice: remove yours and its message. Reword the line through Cart.summary.vat-included.

CheckoutErrorCode holds the orderPlace codes

Section titled “CheckoutErrorCode holds the orderPlace codes”

In: feature-cart 0.14.0

CheckoutErrorCode is TARGET_NOT_FOUND | ORDER_CREATION_FAILED, the codes orderPlace reports, replacing three payment codes it no longer returns. CheckoutError is still exported from ./hooks; update only a deep import of data/use-place-order.ts.

The approvals add-on uses the framework’s order-approval module

Section titled “The approvals add-on uses the framework’s order-approval module”

In: feature-organization 0.9.0

The approval documents read BusinessUnit.orderApprovals and orderApprovalRules and write through the framework’s approval mutations. An older gateway refuses the rule writes.

  • ApprovalQueueOrder is gone: a row is an OrderApproval, with the order under approval.order.
  • useApprovalQueue(state) is useApprovalQueue({ status, page, pageSize }), and its data is { items, pagination, counts }. Use approvalKeys from ./approval/queries instead of approvalQueueKey.
  • ApprovalQueue, ApprovalQueueItems, and ApprovalQueueItem take approvals or approval instead of orders or order.
  • ApproveRejectActions takes the approval instead of orderId and canApprove. approve.mutate and reject.mutate take { approval, reason? }.
  • useApprovalRules({ status, page, pageSize }) only reads. Write with useApprovalRuleActions(): create, update, and setStatus.
  • ApprovalRule drops minimumOrderTotalCents, approverRoleKeys, and active: use condition, approverTiers, and status. ApprovalRuleInput is replaced by ApprovalRuleCreateInput and ApprovalRuleUpdateInput.

The order and quote facts move out of the detail headers

Section titled “The order and quote facts move out of the detail headers”

In: feature-order 0.15.0, feature-quote 0.15.0

OrderDetailHeader and QuoteDetailHeader hold the title and an action slot. The facts, such as the date, the buyer, and the status, moved to OrderDetailInfo and QuoteDetailInfo, which the default layouts render under the header. If you compose the header yourself, add the info part:

<OrderDetailHeader order={order} />
<OrderDetailInfo order={order} />
<QuoteDetailHeader entry={quote} requestedBy={requestedBy} now={now} />
<QuoteDetailHeader entry={quote} />
<QuoteDetailInfo entry={quote} requestedBy={requestedBy} now={now} />

The message keys Order.card.po-reference, Quote.detail.requested-on, and Quote.detail.requested-on-by are gone.

A delivery on the order detail lists its lines

Section titled “A delivery on the order detail lists its lines”

In: feature-order 0.15.0

OrderDetailDeliveries renders a card per line that went out, instead of a list of names and counts. If you render it next to OrderLineItems, the lines show twice: render one or the other. The message keys Order.delivery.contents, shipped-quantity, and outstanding-quantity are gone.

In: feature-account 0.8.0, feature-organization 0.9.0

AddressBookItems and CompanyAddressBookItems render a div of sections under letter headings instead of a two-column ul grid. Their props are typed over div. If your brand styles [data-component="address-book-list"] as a grid, restyle it for the single column. From feature-organization 0.11.0 the company book files its addresses by location, since they all carry the company’s name; pass groupBy="name" to file them by name.

A balance due no longer offers “Change my order”

Section titled “A balance due no longer offers “Change my order””

In: feature-order 0.15.0

isOrderRevisable no longer accepts BALANCE_DUE, matching the states orderRevise accepts: PENDING and FAILED. OrderResume stops offering a revise that could only fail.

The address form checks postal codes and phone numbers

Section titled “The address form checks postal codes and phone numbers”

In: commerce-ui 0.8.0, feature-account 0.8.0

An address that used to pass can now fail, such as a Dutch address with a 5-digit postal code or text in the phone field. A server action that validates with AddressFormSchema rejects it too. Saved addresses are checked again only when edited. libphonenumber-js is a regular dependency of commerce-ui, and feature-account no longer declares it.

The order confirmation parts need createdAt and billingAddress

Section titled “The order confirmation parts need createdAt and billingAddress”

In: feature-order 0.15.0

OrderConfirmationHeader reads the order’s createdAt, and OrderConfirmationNext reads its billingAddress. A page that passes the whole order changes nothing. If you compose these parts with a narrower object, add the two fields.

In: core 1.8.0

SimulateHandlers and CleanupHandlers need every action in the contract. An engine that implements them all itself must add the new ones. A project that uses commercetoolsTestSupport, or overrides single actions, is not affected.

Action In
simulate business-unit/create core 1.8.0
cleanup business-unit/delete core 1.8.0
cleanup customer/delete-by-email core 1.8.0
simulate order/pay core 1.9.0
simulate review/approve and review/reject core 1.10.0
cleanup back-in-stock/delete-by-email core 1.10.0

A new cart starts at the buyer’s defaults

Section titled “A new cart starts at the buyer’s defaults”

In: commercetools 0.20.0

A new cart takes the customer’s, or the business unit’s, default billing and shipping address and the default shipping method for it. It no longer carries a shipping address that holds only the store’s country. A storefront that read the country from cart.shippingAddress reads it from the store context, and shows estimatedShippingCosts until an address is entered.

Deregister copyCustomerDefaultsToCart, which is deprecated, and any extension of your own that copies a business unit’s defaults onto a new cart, from the cart Create trigger. Keep applyDefaultShippingMethod on Update.

The commercetools service client needs more scopes

Section titled “The commercetools service client needs more scopes”

In: commercetools 0.20.0

Scope Why
manage_customers, manage_orders Sign-in and sign-up go through the project, so a guest’s orders are no longer handed to whoever signs in
view_shipping_methods A new cart gets its default shipping method

The business unit order mutations also check the associate’s own permissions. Give the roles that should allow it the matching commercetools permissions:

Mutation Own cart or order A colleague’s
paymentCreate on a cart CreateMyOrdersFromMyCarts CreateOrdersFromOthersCarts
orderRevise UpdateMyOrders, CreateMyCarts UpdateOthersOrders, CreateOthersCarts
orderCancel UpdateMyOrders UpdateOthersOrders

Without the permission, the call answers TARGET_NOT_FOUND.

A cart update is not retried after a version conflict

Section titled “A cart update is not retried after a version conflict”

In: commercetools 0.20.0

Adding or removing a line item, applying or removing a discount code, and any update with a pinned version can answer cartErrors with CART_VERSION_CONFLICT and cart: null where the update used to go through. Refetch the cart and offer the action again. Do not resend it automatically, since it may already have been applied.

In: commercetools 0.20.0, medusa 0.8.0, schemas 0.17.0, sfcc 0.12.0

OrderApprovalRuleInput is removed. orderApprovalRuleCreate takes an OrderApprovalRuleCreateInput, and orderApprovalRuleUpdate an OrderApprovalRuleUpdateInput, which changes only the fields it is given.

Before After
minimumOrderTotalCents: n condition: { clauses: [{ orderTotal: { operator: GTE, amount: { centAmount: n, currency } } }] }
approverRoleKeys: [...] approverTiers: [{ allOf: [{ anyOf: [...] }] }]
  • On commercetools, pass { clientFactory, customTypes } to OrderApprovalModule to write rules. customTypes names your custom type for approval-rule, which needs a String field evolveCondition, and your type for order. The module checks at startup that both exist. Without options it serves the schema only, for a shop without approvals.
  • orderApprovalRuleDelete is deprecated: use orderApprovalRuleStatusUpdate. Reading minimumOrderTotalCents and approverRoleKeys is deprecated in favor of condition and approverTiers.

In: contentful 0.8.0, storyblok 0.7.0

StoryblokModule and ContentfulModule take a required webhookSecret. Set it before you upgrade, or every webhook is answered 401 and published content stops reaching the caches and downstream services.

  • Storyblok: give the space’s webhook a secret and pass the same value.
  • Contentful: turn on request verification for the space’s webhooks and pass its signing secret. The signature covers the request path, so a proxy in front of the service must not rewrite it.

In: core 1.8.0

A service that calls @sentry/node itself must upgrade it to 11.x, so that one SDK is loaded, and follow Sentry’s v10 to v11 migration guide for its own calls. With SENTRY_TRACING=true, Sentry streams spans and names them by its new conventions: review Sentry dashboards, alerts and sampling rules that match on span names or ops. startHttpServer no longer registers an error handler; Sentry’s Fastify integration captures route errors.

core no longer depends on @labdigital/federated-token

Section titled “core no longer depends on @labdigital/federated-token”

In: core 1.8.0, medusa 0.8.0

  • ClientContext declares isAuthenticated(), setAccessToken(token) and load(), which takes no argument. Drop any parameter from the load of a custom client context.
  • ContextValue no longer declares federatedToken. A context type that reads it declares federatedToken?: FederatedToken itself.
  • The Medusa ClientContext.load() no longer accepts a token. It ignored it.

Medusa holds a company’s order for approval

Section titled “Medusa holds a company’s order for approval”

In: medusa 0.8.0

Where the buyer’s company requires approval, the first orderPlace requests it and answers with the pending approval and no order. Handle that response in the storefront. Once the cart is approved, placing it again creates the order. Upgrade @evolve-framework/medusa-plugin-approval to 1.2.0 or later.

In: sfcc 0.12.0

The organization id is read from the environment variable SFCC_ORGANIZATION_ID, no longer from SFCC_ORG_ID. Rename the variable in every deployment before you upgrade.

Meilisearch keeps each document type in its own index

Section titled “Meilisearch keeps each document type in its own index”

In: search-meilisearch 0.3.0

Each document type is written to an index of its own, such as bundles-evolve-nl-nl beside products-evolve-nl-nl. Run a full reindex after you upgrade.

In: mcp-core 1.3.0

createServer (HTTP and stdio) receives setSessionStoreContext as a fourth argument, which a tool calls to switch the store, locale, currency or extra context headers within a session. Existing factories keep working. Code that calls a CreateServerWithContext factory itself, such as a custom transport, must pass the fourth argument.