Repository navigation
chore(deps): Bump the minor-and-patch group with 26 updates - #387
Closed
dependabot[bot] wants to merge 1 commit into
Closed
dependabot[bot] wants to merge 1 commit into
dependabot[bot] wants to merge 1 commit into
Conversation
Bumps Anthropic from 12.45.0 to 12.54.1 Bumps Aspire.Npgsql from 13.5.3 to 13.6.1 Bumps FluentAssertions from 8.10.0 to 8.11.0 Bumps Marten from 9.31.2 to 9.47.0 Bumps Marten.EntityFrameworkCore from 9.31.2 to 9.47.0 Bumps Microsoft.AspNetCore.Authentication.JwtBearer from 10.0.11 to 10.0.12 Bumps Microsoft.AspNetCore.DataProtection.EntityFrameworkCore from 10.0.11 to 10.0.12 Bumps Microsoft.AspNetCore.Identity.EntityFrameworkCore from 10.0.11 to 10.0.12 Bumps Microsoft.EntityFrameworkCore.Design from 10.0.11 to 10.0.12 Bumps Microsoft.Extensions.AI.Evaluation from 10.9.0 to 10.10.0 Bumps Microsoft.Extensions.AI.Evaluation.Quality from 10.9.0 to 10.10.0 Bumps Microsoft.Extensions.AI.Evaluation.Reporting from 10.9.0 to 10.10.0 Bumps Microsoft.Extensions.Configuration.EnvironmentVariables from 10.0.11 to 10.0.12 Bumps Microsoft.Extensions.Configuration.Json from 10.0.11 to 10.0.12 Bumps Microsoft.Extensions.Configuration.UserSecrets from 10.0.11 to 10.0.12 Bumps Microsoft.Extensions.TimeProvider.Testing from 10.9.0 to 10.10.0 Bumps OpenTelemetry from 1.18.0 to 1.19.1 Bumps OpenTelemetry.Api from 1.18.0 to 1.19.1 Bumps OpenTelemetry.Exporter.OpenTelemetryProtocol from 1.18.0 to 1.19.1 Bumps OpenTelemetry.Extensions.Hosting from 1.18.0 to 1.19.1 Bumps OpenTelemetry.Instrumentation.AspNetCore from 1.18.0 to 1.19.0 Bumps OpenTelemetry.Instrumentation.Http from 1.18.0 to 1.19.0 Bumps SonarAnalyzer.CSharp from 10.33.0.1635 to 10.35.0.4138 Bumps Swashbuckle.AspNetCore from 10.2.3 to 10.3.0 Bumps Testcontainers.PostgreSql from 4.14.0 to 4.15.0 Bumps xunit.v3.assert from 4.0.0 to 4.0.1 --- updated-dependencies: - dependency-name: Anthropic dependency-version: 12.54.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Aspire.Npgsql dependency-version: 13.6.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: FluentAssertions dependency-version: 8.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Marten dependency-version: 9.47.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Marten.EntityFrameworkCore dependency-version: 9.47.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer dependency-version: 10.0.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch - dependency-name: Microsoft.AspNetCore.DataProtection.EntityFrameworkCore dependency-version: 10.0.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch - dependency-name: Microsoft.AspNetCore.Identity.EntityFrameworkCore dependency-version: 10.0.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch - dependency-name: Microsoft.EntityFrameworkCore.Design dependency-version: 10.0.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch - dependency-name: Microsoft.Extensions.AI.Evaluation dependency-version: 10.10.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Microsoft.Extensions.AI.Evaluation.Quality dependency-version: 10.10.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Microsoft.Extensions.AI.Evaluation.Reporting dependency-version: 10.10.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Microsoft.Extensions.Configuration.EnvironmentVariables dependency-version: 10.0.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch - dependency-name: Microsoft.Extensions.Configuration.Json dependency-version: 10.0.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch - dependency-name: Microsoft.Extensions.Configuration.UserSecrets dependency-version: 10.0.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch - dependency-name: Microsoft.Extensions.TimeProvider.Testing dependency-version: 10.10.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry dependency-version: 1.19.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Api dependency-version: 1.19.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Exporter.OpenTelemetryProtocol dependency-version: 1.19.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Extensions.Hosting dependency-version: 1.19.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Instrumentation.AspNetCore dependency-version: 1.19.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Instrumentation.Http dependency-version: 1.19.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: SonarAnalyzer.CSharp dependency-version: 10.35.0.4138 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Swashbuckle.AspNetCore dependency-version: 10.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Testcontainers.PostgreSql dependency-version: 4.15.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: xunit.v3.assert dependency-version: 4.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches. Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
Contributor
Author
|
Superseded by #390. |
dependabot
Bot
deleted the
dependabot/nuget/backend/minor-and-patch-a6ea5fddd8
branch
October 15, 2026 15:42
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.
Updated Anthropic from 12.45.0 to 12.54.1.
Updated Aspire.Npgsql from 13.5.3 to 13.6.1.
Release notes
Sourced from Aspire.Npgsql's releases.
13.6.1
What's New in Aspire 13.6.1
Patch release for Aspire 13.6 that reduces dashboard CPU usage during sustained metric ingestion, restores scrolling in the Metrics tree, improves dashboard navigation, fixes container exec watch failures, and ensures session-scoped containers are cleaned up when stopping .NET AppHosts on Windows.
🐛 Fixes
📊 Dashboard CPU usage could increase during long-running metric ingestion — Metric retention repeatedly scanned retained history on every insertion, causing steadily increasing CPU usage even with a fixed workload. Cleanup now skips dimensions below capacity and removes only the oldest surplus points when needed. Existing retention limits and exemplar behavior are unchanged, and no configuration changes are required. Regression introduced in 13.6. Fixes #20725. (#20747, backport of #20736, @JamesNK)
📈 The Metrics tree could not be scrolled — The meter and instrument tree now scrolls when it exceeds the viewport, allowing you to reach and select instruments below the fold. Regression introduced in 13.6. Fixes #20728. (#20762, backport of #20758, @heyysiri)
🧭 Dashboard navigation could fail after a browser disconnect — Pending page-state updates now persist session state before navigating and skip navigation when the browser has disconnected, avoiding an unhandled navigation failure. The navigation rail's overflow button also has consistent sizing, icon alignment, and hover styling in expanded and collapsed layouts and both light and dark themes. (#20545, backport of #20527, @JamesNK)
🖥️ Container exec watches could terminate shortly after AppHost startup — A stalled DCP watch connection could produce a critical
Watch task over Kubernetes ContainerExec resources terminated unexpectedlyerror and stop subsequent terminal state and log updates from being observed. Watch connection attempts now retry after timeouts, and periodic restarts correctly recreate connections without swallowing unrelated cancellation. Regression introduced in 13.6.0. (#20664, backport of #20466, @radical)🪟 Session-scoped containers could remain running after stopping a .NET AppHost on Windows — AppHosts launched through
dotnet runordotnet watchnow allow DCP to finish resource cleanup during shutdown, including existing Ctrl+C andaspire stopflows. Persistent resources remain unaffected, while direct .NET launches and TypeScript/polyglot AppHosts retain their existing process protection. Fixes #20495. (#20514, backport of #20494, @danegsta)Full Changelog: v13.6.0...v13.6.1
Full commit: 3751e615ad660621f2a7aa4c390ef48e08a0eed8
13.6.0
Aspire 13.6.0
Aspire 13.6 brings persistent application history, a refreshed and more interactive dashboard, first-party Java and Rust hosting, and new Azure deployment options. Coordinated .NET builds, portable volume paths, sharper CLI workflows, and more capable editor tooling make it easier to build, debug, and deploy applications across languages.
Highlights
WithRepl()commands open bundled clients for PostgreSQL, MySQL, MongoDB, SQL Server, Redis, and Valkey, whileaspire terminal psandaspire terminal tape playsupport discovery and repeatable terminal interactions.Aspire.Hosting.JavaandAspire.Hosting.Rustpackages bring Maven, Gradle, Spring Boot, Quarkus, and Cargo applications into the app model, with generated container builds and VS Code debugging. These integrations build on work that originated in the Aspire Community Toolkit.Aspire.Hosting.Dotnetintegration coordinates compatible projects into shared restore and build groups and supports .NET SDK container publishing. Portable volume-path environment variables work across local execution and deployment, while TypeScript AppHosts gain standardappsettings.jsonconfiguration and Deno runtime support.aspire runandaspire start, update repository-local CLI manifests withaspire update, create file-based C# AppHosts withaspire init --language csharp --file-based, and export TypeScript API data withaspire sdk export. Terminal commands no longer need a feature flag, Linux certificate trust includes Firefox NSS databases, andaspire stop --force --volumesadds explicit cleanup of Aspire-owned volumes.ASPIRE_HOME, Kubernetes preserves inherited hostnames and embedded parameter values, and AKS gains persistent-volume provisioning and more reliable cleanup.Notable changes include automatic TLS for local MongoDB servers when a certificate is available, the Linux-based vNext Cosmos DB emulator becoming the default, new Azure Front Door origin names that can require cleanup of existing origins, portable connection-string environment-variable aliases on stricter deployment targets, and experimental terminal types moving from
Aspire.Hosting.TerminalstoAspire.Hosting.ApplicationModel.See the full list and migration guidance in the Aspire 13.6 breaking changes.
📖 Learn more
For complete details, examples, migration guidance, and everything new in this release, read What's new in Aspire 13.6.
Thank you to all the community contributors who helped make Aspire 13.6 possible! 💜
Full Changelog: v13.5.4...v13.6.0
Full commit: 56f3e9c0d216c0c7069dabb49dd0464e4827744f
13.5.4
What's New in Aspire 13.5.4
Patch release for Aspire 13.5 that fixes Kafka health-check resource leaks, DevTunnel errors with automatically selected regions, misleading Azure emulator dashboard entries, and unintended changes to generated starter apps, plus Homebrew compatibility and Radius API diagnostic updates.
🐛 Fixes
📨 Kafka health checks leaked producers and polling threads — Each AppHost health-check execution created a new Kafka producer without disposing it, accumulating background threads over time. Health checks now reuse a producer per Kafka resource and dispose it with the AppHost, while keeping multiple Kafka resources independently configured. Fixes #20091. (#20094, backport of #20092, @davidfowl)
🌐 DevTunnels could fail when the region was selected automatically — Tunnel setup and health checks now use the cluster-qualified tunnel ID returned by the DevTunnel CLI for port operations and access queries. This fixes failures when a bare tunnel ID cannot be resolved for those operations. Regression introduced in 13.3. Fixes #18790. (#19853, backport of #19230, @Vladipz)
☁️ Emulator-only AppHosts showed an unused Azure environment — The dashboard now hides the
azure-environmentresource when no Azure resources require cloud provisioning, instead of leaving it visible in Not started. It remains visible for apps that combine local emulators with resources requiring Azure provisioning. No AppHost changes are needed. Fixes #19617. (#19998, backport of #19843, @eerhardt)🧩 Starter app generation could alter unrelated JavaScript values — Dynamic port replacement could also replace matching numeric literals in bundled JavaScript, including Bootstrap timing values. Port substitutions are now restricted to
localhost:URLs, preserving the original library files while still configuring the requested ports. Fixes #20030. (#20110, backport of #20031, @bart-vmware, @JamesNK)🍎 Updated the Aspire Homebrew cask for Homebrew 6.x — Replaced deprecated cask URL and post-install syntax with the supported equivalents, resolving compatibility issues with current Homebrew while preserving install-channel metadata. (#20119, backport of #19965, @askpt, @joperezr)
🧪 Radius cloud-provider callback interfaces now carry the experimental diagnostic —
IAwsRadiusProviderBuilderandIAzureRadiusProviderBuilderare now marked withASPIRERADIUS003, matching the existingWithAwsProviderandWithAzureProvidermethods. Code referencing these interfaces directly must now acknowledge the same experimental API diagnostic. (#19874, @sebastienros)Full Changelog: v13.5.3...v13.5.4
Full commit: 9c1b401dd67746739044f68959cbf4d3d7af93a6
Commits viewable in compare view.
Updated FluentAssertions from 8.10.0 to 8.11.0.
Release notes
Sourced from FluentAssertions's releases.
8.11.0
What's Changed
New features
ThatSatisfyfor methods and properties by @jnyrup in AddThatSatisfyfor methods and properties fluentassertions/fluentassertions#3257Improvements
Fixes
HavePropertyonJsonArrayby @jnyrup in Fix exception onHavePropertyonJsonArrayfluentassertions/fluentassertions#3295Documentation
Others
string.Formaton failure by @jnyrup in Correct the arguments passed tostring.Formaton failure fluentassertions/fluentassertions#3325New Contributors
Full Changelog: fluentassertions/fluentassertions@8.10.0...8.11.0
Commits viewable in compare view.
Updated Marten from 9.31.2 to 9.47.0.
Release notes
Sourced from Marten's releases.
9.47.0
The
FetchForWriting/FetchLatestconsistency release, plus a bounded async-daemon shutdown.Read the behaviour changes before upgrading. Two of them can change how your projections and
subscriptions behave on every deployment, and two more refuse a batch shape that used to be accepted.
Subscription and projection drains are now bounded by
StopAndDrainTimeout([#5610])Via JasperFx 2.81.0 (jasperfx#953 and jasperfx#983). When a shard stops — host shutdown, or reassignment
to another node — the page in flight finishes, pages still queued are skipped and resumed by the next
owner from committed progression, and a page still running at
Projections.StopAndDrainTimeout(default 5 seconds) is cancelled with its transaction rolled back.
This fixes a real failure: a node that loses a shard's lock no longer keeps applying its backlog
alongside the new owner, an overlap that could end in
ProgressionProgressOutOfOrderExceptionand aStopped shard. Graceful shutdown is also bounded now, rather than waiting out the whole backlog and
potentially overrunning a Kubernetes termination grace period.
If your projection or subscription pages take longer than 5 seconds, raise the timeout:
Otherwise those pages are cancelled and re-processed on every shutdown and rebalance. Delivery was
always at-least-once, so no guarantee changed, but duplicates become much more likely — and side effects
performed outside the Marten session (HTTP calls, sends that bypass the transactional outbox) are not
rolled back with the page. Note this applies to async projections as well as subscriptions; the upstream
note covers only subscriptions and is out of date.
A batched
FetchLatestor expected-versionFetchForWritingmust be first in its batch ([#5604])For an aggregate projected with
ProjectionLifecycle.Asynconly. Both now bracket their reads inbegin transaction isolation level repeatable read read only…endso those reads share one snapshot,and PostgreSQL accepts that only as a transaction's first statement. So:
batch.Events.FetchLatest<T>(id)andbatch.Events.FetchForWriting<T>(id, version)have to be thefirst operation in their batch, and
FetchForExclusiveWriting.Both are refused at the enlisting call, naming the call to move, rather than surfacing later as a bare
25001. Inline and Live aggregates are unaffected, and inside a caller-owned transaction no bracket isemitted so neither rule applies. If you batch a
FetchLatestbehind aLoad, move it to the front.New
SnapshotRaceExceptionfrom a batched exclusive fetch ([#5613])A batched
FetchForExclusiveWritingon an Async aggregate now throwsMarten.Exceptions.SnapshotRaceExceptionin the rare case where the daemon commits a snapshot between that batch's two reads. Retry the batch, or
fetch outside a batch — outside a batch Marten retries for you and you will never see it.
... (truncated)
9.46.0
Mostly a resiliency and Native AOT release. Five behaviour changes — the retry ones are the most likely to be noticed, because Marten now surfaces failures it used to absorb.
Behaviour changes
A command timeout is no longer retried on reads (#5566, #5580). An attempt that timed out has already spent the whole
CommandTimeout, so retrying it three times held the caller for four timeouts instead of one. This covers both shapes: Npgsql's client-sideCommandTimeout, and a server-sidestatement_timeout, which arrives as57014 query_canceledwith noTimeoutExceptionanywhere in the exception. Connection-pool exhaustion arrives in the same shape and so is no longer retried either — a deliberate trade, documented in the resiliency guide along with what to do instead.Sticky, ambient and external session lifetimes now fail loudly (#5582, #5598), via the new
SessionTransactionUnusableException. Two things used to go wrong silently. A broken connection reportedConnectionState.Closed, so Marten reopened it — onto a different backend — and handed the command the stale transaction, which Npgsql accepts; aSerializablesession then quietly answered from a newer snapshot. And a command timeout inside a transaction aborted it, after which every later call returned a bare25P02naming neither the timeout nor the way out. For caller-owned transactions Marten records the cause and reports it but rolls nothing back — the scope is still yours.The async serializable session builders now produce a serializable session (#5594).
OpenSerializableSessionAsync(new SessionOptions())previously returned a session that was neither serializable nor auto-closing: it held one connection open for its lifetime with no transaction. These two methods now pinIsolationLeveltoSerializableand begin the transaction eagerly. A non-Serializable level passed to them is overridden rather than silently honoured.The async daemon spends one retry budget instead of two (#5593).
ResilientEventLoaderand theQuerySessioninside it were both given the same pipeline, so a handled failure ran up to sixteen times.A retried write no longer accumulates exceptions across attempts (#5591). The exception list was shared, and
ExecuteBatchPagesAsyncbranches on its count — so one operation failing twice turned a rethrow into anAggregateException, making the caller's exception type depend on how many retries happened.Native AOT
Strong-typed document ids now work (#5589, #5579), with one registration per document type:
Previously a single strong-typed id anywhere in the store killed the application while the first document's mapping was built. The identity path closes a chain of generics over your id type, and a native image has no instantiation for them unless something roots it; naming all three types is what roots them. Under a JIT the call does nothing — unregistered types still take the reflective path. Not yet covered: F# single-case discriminated-union ids, and
.IsOneOfover a strong-typed id. The intent is forMarten.SourceGeneratorto emit these registrations so the call becomes unnecessary.Also AOT: a decimal comparison in a LINQ filter is documented with a tested workaround (#5597) — it is the BCL expression-tree factory rather than Marten, but it only shows up from a native binary. Marten's AOT runtime gate now covers strong-typed ids and decimals, so these stay pinned.
Fixes
PrefixSearchquotes each word as a tsquery lexeme (#5571, #5568), so a search box containing&,|,!,(,:or a tab no longer produces42601: syntax error in tsquery. Not an injection — the term was already a parameter — but the documented contract says each word is treated as a prefix, and raw input has to be escaped to honour that.AdvisoryLockshutdown release is bounded, and the vendored copy moves back to Weasel (#5572, #5576).catch-and-Console.WriteLine-and-rethrow blocks removed (#5584) — they bypassedIMartenSessionLoggerand any configuredILogger, and one of them also closed a connection on the line above the one that opened it.Dependencies
JasperFx 2.80.2 (#5590) and Weasel 9.41.0 (#5596, #5576). Both carry Native AOT work of their own on the identity path — JasperFx's
ValueTypeInfowrappers and aggregate identity sources, Weasel's non-genericIIdentificationfacade.🤖 Generated with Claude Code
https://claude.ai/code/session_01481eiEZg1Bv6pu4DrgPRg3
9.45.0
This one is largely the community's release. Four of the six changes below were found, diagnosed, or fixed by people outside the core team, and two of them are bugs that would have been very hard to find from the inside.
Community contributions
@Hawxy — two LINQ regressions (#5556). A captured nullable in a
whereclause was throwing: aNullable<T>never survives boxing, so an empty one boxes tonullandPropertyInfo.GetValuehad no target, breaking the thoroughly ordinarywhere !captured.HasValue || x.Id == captured.HasValueandValueare now read off the boxed form. The same PR fixes literals in select statements surviving paging, stats, and version select clauses.@Hawxy — inline-to-async on an empty database (#5561).
FetchHighestEventSequenceNumberreadmt_events_sequence.last_value, which PostgreSQL reports as1withis_called = falsebefore anything has drawn from the sequence.SubscribeAsInlineToAsyncused that as its starting position, so on an empty store the shard started at 1 against a high water mark of 0 and the agent failed with "The last committed number (1) cannot be higher than the high water mark (0)". A new store is exactly when you least want that.@tomasherceg — ordering after a grouped projection (#5557, shipped as #5563).
CompileGroupBytransferred the downstreamLimitandOffsetbut never theOrderingExpressions— even though the comment sitting over that block had claimed OrderBy was transferred for as long as it existed. AGroupBy(...).Select(...)that was then ordered came back in whatever order PostgreSQL felt like, with noorder byin the SQL and no error, so a paged one took an arbitrary page.Tomáš found it, diagnosed it, and landed the hard part — re-expressing the ordering against the projected shape rather than the document. He also flagged his own uncertainty about edge cases, which is what sent us looking and turned up two more: a scalar projection (
Select(g => g.Key),Select(g => g.Count())) has no projected members, so ordering one threw instead of ordering by its single value; andOrderBySql()reportedInvalid OrderBy() expression ''. Both now work. His commit is in the tree with his authorship.@chrisbbe — the identity probe's side effects (#5562). The best bug report we have had in a while: a minimal repro, the stack trace, the mechanism, and a correct suggested fix.
Identity resolution handed its candidate filter to a traversal that applies it to every property and field, and only afterwards picks the id by
[Identity]or by the nameId. That filter is not free to ask — for any public struct shaped like a strong-typed id it registers the type on the globalPostgresqlProvidersingleton and closes an open generic. So an ordinary non-identity property got remapped process-wide the moment its document or event type was mapped, turning anOptional<string>used only for a nickname intovarcharfor everything, LINQ included. Under Native AOT the generic construction brought startup down outright with aMissingMethodException.Both probes now split into a pure shape test and the effectful registration; the traversal asks the cheap question and only the chosen member gets the expensive one.
RegisterValueTypefillsStoreOptions.ValueTypesbut has never registered the Postgres mapping, so a value type used as a duplicated field rather than as an id only ever worked because the probe happened to reach it on some document. If you callopts.RegisterValueType<T>()you were doing the right thing and relying on an accident. That registration now belongs toRegisterValueType.Performance
Batch reads are one round trip again (#5550). JasperFx 2.79 added
LoadManyAsynctoIDocumentReadOperationsandFetchManyForWritingtoIEventStoreOperations, both default-implemented. The defaults are correct, and both make one round trip per id.Marten has sixteen
LoadManyAsyncoverloads and not one of them takes the token last, so the contract's(ids, token)call matched none of them and silently bound to the default. Nothing failed — the shared compliance suite loads 2,500 documents through it, 2,500 round trips at a time, passing.LoadManyAsync, 25 idsLoadManyAsync, 2,500 idsFetchManyForWriting, 10 streamsFetchManyForWritingis new public surface on Marten: one handle per id in the order asked for, a handle (not a gap) for a stream that does not exist yet, and each handle keeping its own starting version soSaveChangesAsyncguards every stream it appended to and no other.::: One lifecycle keeps the sequential shape
An aggregate projected with
ProjectionLifecycle.Asyncis fetched insidebegin transaction isolation level repeatable read read only, and PostgreSQL only accepts that as the first statement in a transaction — so two of them cannot share a batch.FetchManyForWritingdetects that lifecycle and falls back to fetching sequentially: same results, same ordering, same per-stream guards, no round-trip saving.Inline,LiveandSnapshotget the fast path.:::
See FetchManyForWriting and Loading Documents by Id for the details.
Also
Dependency bumps from Dependabot:
fast-uri(#5558),brace-expansion(#5559),dompurify(#5560).9.44.0
Bumps the JasperFx family to 2.79.1 and lands three fixes. Two of them change behaviour, one in a way that changes what a query returns.
Fixes
#5549 — a nested
Any()with a plain equality silently returned nothing. A sub-query is parsed against a member tree rooted at the element type, so insideMiddles.Any(m => m.Bottoms.Any(...))theBottomsmember reportsd.data -> 'Bottoms'— within that parse,d.datastands for oneMiddle. Nothing in the member tree records thatBottomslives underMiddles; the containment filter is re-anchored when the enclosingAny()lifts it out. That re-anchoring moved the jsonb payload but left the locator pointing at the inner collection, so the query went out asWell-formed SQL against a key the document does not have. No error, no rows.
Three shapes of the same query diverged, which is what made this hard to pin down from the outside: a sibling predicate (
m.Color == Blue && m.Bottoms.Any(...)) built the containment through a different path and was always correct,StartsWithis not containment-eligible and fell to a jsonpath filter that re-rooted properly, and only the plain single-equality nestedAny()was wrong.Four more failures came out of the same defect once the generated SQL was dumped across every nesting shape:
Any()negated, or as anORbranch, or three levels deepm.Bottoms.Any(x) && m.Bottoms.Any(y)— the workaround suggested in the issueNotSupportedExceptionAny()/Contains()beside a sibling predicateNullReferenceExceptiont.Xs.Any(p) && t.Xs.Any(q)now matches when two different elements satisfy the two predicates. That is what the query asks for, and it is more rows than 9.43 returned. If you were relying on the old answer, you wantedt.Xs.Any(x => p(x) && q(x)).Diagnostics surface (monitoring consoles)
jasperfx#932 —
DocumentTypesAsynclists document sub-classes. The contract was silent on this and the stores split: Polecat listed sub-classes, Marten and Fisher did not, and a store-agnostic type picker could not tell which answer it had. Settled in favour of listing them, because every member taking adocumentTypeNamealready accepts a sub-class name and narrows to its rows — a picker that could not offer one was hiding a capability the contract guarantees.Marten now emits an entry per registered sub-class alongside each mapped root. A sub-class entry carries its own
mt_doc_typealias — the discriminator its rows actually hold, which is the string you pass back toQueryDocumentsAsync— and the root's schema, because the root's table is where those rows live.DocumentTypeRef.RootTypeNamenames the root and isnullfor a root itself;IsSubClassreads it.DocumentTypesAsyncthan it did in 9.43.IsSubClasstells them apart.RootTypeNameis init-only, so the positionalDocumentTypeRefshape a store compiled against an older JasperFx calls is unchanged.Event sourcing
A composite projection could intermittently pause and stop advancing (jasperfx#938).
ProjectionExecutiondisposed its batch unconditionally through anawait using. For a composite member that batch is the parent composite's, shared by design — so the member's scope-exit disposal raced the parent's execute, which then threwObjectDisposedExceptionout ofBlock.WaitForCompletionAsyncand left the shard Paused with no progression row at all.It takes a member on that path, so the exposed shape is a composite of an aggregation plus a plain event projection; an all-aggregation composite runs on
GroupedProjectionExecution, which already guarded the disposal. Intermittent because the stages run in parallel and the race can fall either way — measured at roughly one run in eight on one such composite.If you run composite projections with a non-aggregation member and have seen a shard quietly stop advancing, this is a strong candidate. Fixed in JasperFx 2.79.1.
Dependencies
JasperFx 2.79.1. Alongside jasperfx#932 and jasperfx#938 above: jasperfx#930 adds
LoadManyAsynctoIDocumentReadOperationsandFetchManyForWritingtoIEventStoreOperations, jasperfx#931 default-implements the 2.77IDocumentStoreDiagnosticsmembers so a store built against an older JasperFx still loads, and jasperfx#933 ratchets abstract interface members so contract growth stays deliberate.The new members arrive default-implemented and Marten has not yet overridden
FetchManyForWriting/LoadManyAsync— the defaults are correct but call the single-id member in a loop. Batching them against Marten's existing batch-query API is tracked separately.9.43.0
Bumps the JasperFx family to 2.78.0 and lands four issues, one of them a data-corruption fix worth reading even if you skip the rest.
Fixes
#5539 — a zero-event quick append could permanently wedge a stream.
mt_quick_append_eventscalled with zero events readmt_streams.versionwithout a lock and ended with a blind write-back, so under READ COMMITTED it could overwrite a concurrent appender's version and leave the stream row below its own events. Every later append then computed a version that already existed and failed onpk_mt_events_stream_and_version— permanently, with no recovery short of repairing the row by hand. A non-empty append could never do this: its first insert collides on that same primary key and rolls back, which is why only the empty call was exposed. The write-back is now skipped when nothing was appended, and usesgreatest()so it can never lower a version whoever calls it.Field context: a production console on 9.32.0 sat at
mt_streams.version608676 againstmax(mt_events.version)608678 for 42 days, roughly 28 failed appends a minute. If you have a stream failing every append on that constraint, this is likely why.#5541 —
ShardState.LastUpdated, liveness rather than progress.Sequencecannot distinguish caught up with nothing new from no longer maintained: both hold the same number forever. The progression row'slast_updatednow reachesShardStateandProjectionProgressRow, and — the part that needed a product change — an idle high-water cycle now restamps theHighWaterMarkrow. Previously an idle cycle issued no SQL at all, so that stamp froze at the last real mark advance and read as "abandoned weeks ago" on a perfectly healthy store. The restamp never toucheslast_seq_id, so it cannot nudge the mark.Diagnostics surface (monitoring consoles)
#5543 —
IDocumentStoreDiagnosticsadopts the defined contract (jasperfx#870). Five behaviours were previously "whatever the store happened to do", and Marten was on the wrong side of all five:""tenant""id::text = @idAlso:
LoadDocumentAsyncreturningStoredDocumentwith metadata, populatedDocumentQueryResult.Documents, a newIDocumentStoreDiagnosticsWriter(save-from-JSON and delete through a normal session, with an expected-version guard),DocumentStoreUsage.SerializerCasing, and structured index / duplicated-field descriptors. Query criteria Marten cannot yet translate are refused rather than silently ignored.#5544 —
DocumentQueryOptions.AllTenants. The explicit replacement for the all-tenants read that #5543 removed. Conjoined tenancy reads every tenant, ordered by tenant then id so paging cannot repeat a row. A store spreading tenants across databases refuses rather than quietly returning only the default tenant's rows.TenantIdnow means the default tenant, not every tenant. If you relied on the old behaviour, setAllTenants = true.Also
#5542 — asynchronous aggregate events are ordered by stream sequence.
Internals: a diagnostic document read now resolves a tenant's database through
TryFindDatabaserather thanFindOrCreateDatabase, so asking a read-only question about an unknown tenant can no longer provision that tenant.9.42.0
Mostly fixes, and two of them only became visible once the one underneath them was gone. Nothing here requires action on upgrade unless you use
IsolationLevel.RepeatableReador above, or batch aFetchForWritingfor an Async-snapshot aggregate.Migrations settle again on a long schema name
#5536.
ApplyAllDatabaseChangesOnStartup()against an already-migrated schema could fail with:The foreign key was not the problem. PostgreSQL truncates identifiers at 63 characters, so a longer
DatabaseSchemaNamewas stored truncated while Marten went on querying for the name it had asked for — found none of its objects, concluded they were all missing, and re-issued DDL the server resolved against the truncated schema, where they already existed. The first apply passed and the second failed, with an error pointing nowhere near the schema name.DatabaseSchemaNameis now truncated to 63 characters so the two sides agree. This does not move anyone's data: the server was already truncating it, and Marten now simply uses the name the server actually stored. Two distinct long names sharing their first 63 characters still collide, exactly as they already do in PostgreSQL.The apply-changes lock waits long enough to be useful
#5529. The advisory lock guarding startup migrations retried on a fixed 50 / 100 / 250ms ladder — about 400ms to win it. That is ample for the multi-replica rolling deploy it was designed for, where the loser only has to outlast a peer's finished migration. It is not enough when more than one store shares a database inside one host, where the loser has to outlast a migration that is still running: it failed startup, and the message's own advice (
ResourceMigrationFailureMode.ContinueOnFailures) would have started the application against a half-migrated schema.New knob, defaulting to 10 seconds:
This was held back until it could be measured. While weasel#659 was unfixed the lock was stranded by any migration that threw, and a longer wait provably changed nothing. Weasel 9.37.0 releases it on the failure path, and only then did the residue show up as a genuine race worth budgeting for.
RepeatableReadupwards#5528, completing what 9.41.0 started. Marten's retry replays the operations it has already computed, not the application code that computed them — and from
RepeatableReadup, the session's transaction is pinned to one snapshot. So any successful replay commits decisions derived from a snapshot that no longer exists. That is exactly the silent lost update 9.41.0 fixed for40001, and40P01(deadlock) had the same flaw for the same structural reason.The write-retry pipeline is now skipped entirely for
RepeatableRead,SerializableandSnapshot. This is deliberately broader than refusing those two SQLSTATEs: class 53, 55, 57P03 and 58 all abort a snapshot-holding transaction too, so singling out class 40 would have left the identical hole open one error code over.If you use those isolation levels, expect to see failures surface that were previously retried away. Handle them by re-reading and recomputing — the only place a snapshot conflict can be resolved.
ReadCommittedis the default and is unchanged: it takes a fresh snapshot per statement, so replaying precomputed SQL still means what it meant, and every existing application keeps full retry behaviour.A batched Async-snapshot
FetchForWritingsays what it needs#5535. For an aggregate projected with
ProjectionLifecycle.Async, the non-exclusiveFetchForWritingwraps its reads inbegin transaction isolation level repeatable read read only…endso they share one snapshot — and PostgreSQL accepts that only as the first statement in a transaction. Enlisted after anything else in a batch, it failed atExecute()with25001: SET TRANSACTION ISOLATION LEVEL must be called before any query, naming an isolation level the caller never mentioned and saying nothing about ordering. Nothing aboutCreateBatchQuery()hints that one of its members has to go first.It is now refused at the enlisting call, with a message that names the aggregate and the constraint. The position that worked still works.
Dependencies
Weasel 9.37.0, whose weasel#659 is the reason most of #5529 went away:
ApplyAllConfiguredChangesToDatabaseAsyncreleased the global migration lock only on its success paths, so a migration that threw left it held and locked every other replica out of migrating — while the node that stranded it reported nothing. Disposing the connection was not enough, because Npgsql resets a pooled connection when it is next used rather than when it is returned, so the lock outlived the apply for as long as that connection sat idle.Also in 9.37.0, and worth reading if you use them: SQL Server 2025 JSON indexes are no longer emitted as
DROP INDEXon every apply (weasel#661), Oracle descending indexes and co-migrated views settle (weasel#660),TableDelta.HasChanges()answers instead of throwing for a table that does not exist yet (weasel#658), and the reconnection loop no longer abandons a connection per attempt (weasel#664).Housekeeping
DISABLE_TEST_PARALLELIZATIONis gone from the CI workflow and the contributor docs. Nothing ever read it, so it looked like a control and was not one — including to us, while diagnosing #5529. Test parallelisation is disabled byCollectionBehaviorinAssemblyInfo.cs, and both files now say where to change it.9.41.0
Upgrade if you use
IsolationLevel.Serializable. The first item below is a silent lost update, and it has been present since the write-retry pipeline shipped. The two items after it change behaviour you may be relying on.🛑 Data integrity:
Serializablesessions could silently lose an update#5528. A session opened with
IsolationLevel.Serializable(orRepeatableRead) did not reliably protect against a lost update. PostgreSQL detected the write conflict correctly and Marten discarded the detection by retrying.Two serializable sessions each load the same document at
Amount = 100. One commits100 - 500. The other should be refused withConcurrentUpdateException; instead it committed100 - 350on top, and the first session's write was gone with no error raised anywhere. From the server's own log:WriteRetryClassifier(#5262) listed40001 serialization_failureas safe to replay, on the reasoning that the server had rolled the transaction back and said so — which is true, and turned out to be necessary but not sufficient. A replay re-issues the operations already computed, rather than re-running the application code that produced them, and a serialization failure means precisely that the snapshot those operations were derived from is no longer a valid basis for them. The replay opens a new transaction with a fresh snapshot, so the conflict is gone and the write lands.40001is now never replayed and surfaces asConcurrentUpdateException, which is what Marten already translated it to. If you opted intoSerializableyou should expect to start seeing that exception — handle it by re-reading and recomputing, which is the only place the conflict can be resolved. Nothing inside Marten requests these isolation levels, so the async daemon and every defaultReadCommittedsession are unaffected.40P01 deadlock_detectedstays retryable deliberately: a deadlock aborts over lock ordering rather than a rejected snapshot, and replaying it is the textbook remedy atReadCommitted. A deadlock retry underSerializablereplays stale-snapshot work for the same structural reason, and the honest fix needs the isolation level plumbed into the classifier — recorded as a known gap rather than guessed at.This went unnoticed because the test that catches it lives in
StressTests, which has had no CI job since 2026-08-08.#5526.
Events.UseAdvisoryLockTransactionnow defaults to false, soHotColdleader election uses a session-scopedpg_try_advisory_lockrather than a transaction-scopedpg_try_advisory_xact_lock. The transaction-scoped lock had been the default since 8.37.3 (April 2026).The reason is what the transaction-scoped lock costs while it works: the leader holds an open transaction for as long as it holds leadership, which on a long-lived daemon is an indefinitely long-running transaction sitting on the connection — with everything that implies for vacuum and for anything watching transaction age.
The transaction-scoped lock is still the better fit behind PgBouncer in transaction pooling mode, which can hand a session-scoped lock's server connection to another client. If that is your deployment, opt back in explicitly:
DefaultTenantUsageDisabledExceptionis no longer aMartenException#5514.
Marten.Exceptions.DefaultTenantUsageDisabledExceptionnow derives fromJasperFx.Events.DefaultTenantUsageDisabledException.JasperFx.Eventscarries this exception so that code can handle the refusal once across Critter Stack stores, and its own contract is that stores subclass it. Polecat did; Marten did not. The consequence was not an error anywhere — a store-agnosticcatch (JasperFx.Events.DefaultTenantUsageDisabledException)compiled, read as if it handled the refusal, and let it through unhandled on Marten only. That is the failure mode this fixes.Multiple inheritance is not available, so it is one base or the other, and the cross-store catch was judged worth more than the marker base. If you rely on a broad
catch (MartenException)to handle this refusal, it will no longer be caught — catch the exception itself, or the JasperFx base. The message is unchanged, including the single-argument overload's behaviour of appending to the standard prefix.Also gone with the reparenting: the
protected (SerializationInfo, StreamingContext)constructor, because the JasperFx base declares none to chain to. Binary serialization of exceptions has been obsolete since .NET 8.... (truncated)
9.40.0
Minor rather than patch for one reason: the source-generated
DetermineActionnow decides one action per batch rather than per event. See the behaviour change below before upgrading if you archive streams from a projection.Archiving projections: one action per batch, not per event (JasperFx/jasperfx#889, via the JasperFx 2.75.2 bump). The source-generated
DetermineActionused to decide per event; it now decides once per batch. This changes what an archiving projection does when a single batch mixes an archive with later events for the same stream.StreamArchivingCompliancegained facts for it and Marten passes them, but if you depend on the old per-event evaluation, test before upgrading.TenantIdStyleis now applied where the tenant id is stamped and keyed, not only where a tenant is resolved (#5516). UnderForceLowerCase, these three previously wrote or matched the raw id:BulkInsertEventsAsync/BulkInsertEventStreamAsyncresolved the right database or partition and then stamped the raw id on everymt_streams/mt_eventsrow — rows invisible to any normalised read under conjoined tenancy, and the wrong key inside the right partition underUseTenantPartitionedEvents.TenantIsOneOf(...)filtered on the raw values, so a mixed-case id matched nothing.DeleteAllTenantDataAsyncused the raw id as itsDELETE ... WHERE tenant_id = :pparameter, so it matched no rows and reported success — the one to look at hardest, since callers are usually honouring an erasure request.If you have been calling these with mixed-case tenant ids, data already written under the raw casing stays where it is; it will not be found by a normalised read.
ForTenant(string)also now normalises its nested-session cache key, which makesForTenant("RED")andForTenant("red")one session rather than two.Event store
IEventStore.OpenReadOnlyEventStore(tenantId)is implemented (#5513). WithAdvanced.DefaultTenantUsageEnabled = false— the automatic state once database-per-tenant tenancy is configured — the entireIReadOnlyEventStoresurface was unreachable, because the tenant-less overload opens the store's default session and is refused before any tenant scope applies. That is whyQueryStreamStates(tenantId)'s own parameter could not work around it. A null tenant keeps the previous store-global behaviour.Diagnosing a missing source-generated dispatcher
The JasperFx 2.75.2 bump (#5518) carries three changes that came out of #5495, where a user's aggregates compiled with no dispatcher and the runtime message could not tell them why:
[assembly: JasperFxSourceGeneratorApplied]in every assembly it processes, so "the generator never ran in that assembly" — a csproj problem — is distinguishable at runtime from "the generator ran and declined your type" — a code-shape problem. The exception says which.CS0433. This happens when a project references the standaloneJasperFx.Events.SourceGeneratorpackage as well as Marten, which bundles it: both copies emit identical file paths and the file-scoped evolvers mangle to the same name. If you hit that error — recognisable because it names the same assembly on both sides — remove the standalone package reference; Marten already carries the analyzer.<JasperFxEventsRequireSourceGenerator>true</JasperFxEventsRequireSourceGenerator>on projects that declare aggregates, and a missing analyzer becomes build errorJFXEVT900rather than a failure at the firstFetchForWriting.Compliance coverage
Marten is now enrolled in
DocumentConjoinedTenancyCompliance(#5517) — the first shared document coverage of conjoined tenancy on any store — with all 10 facts running.ConjoinedEventTenancyCompliancegoes from 16 passing with 2 skipped to 18 passing with none, the two skips having been waiting on the read-only overload above.Two of these enrollments exposed that Marten's own commit-listener compliance facts had been passing vacuously — the harness never installed the listener the suites register, so "no phantom deletion was reported" was trivially true of a store reporting nothing at all. Fixed in the #5518 bump; no product change was needed, and both halves of that fact now pass for real.
Dependencies
JasperFx 2.75.2 and Weasel 9.35.2.
Weasel 9.35.x is mostly EF Core and SQL Server work, plus weasel#634: an exhausted
DropSchemaretry is now reported instead of returning success.Docs
The bundled analyzer does flow transitively across a
ProjectReference(#5508) — the composite-configuration page claimed the opposite. The claim was true of the standalone analyzer package, which Marten setsPrivateAssets="all"on, but #4557 bundles the analyzer DLL into Marten's own package and that copy flows.9.39.1
What's Changed
Full Changelog: JasperFx/marten@V9.39.0...v9.39.1
9.39.0
Security release
This release fixes two critical SQL injection vulnerabilities in Marten's LINQ provider. Both were reported privately and are disclosed today alongside this version. If your application routes untrusted input into either surface below, upgrade.
GHSA-q4xm-rhx9-xjm4 — SQL injection via a GroupBy HAVING operand (critical)
Affects 9.13.0 – 9.38.0. Fixed in 9.39.0.
A
GroupBy(...).Where(g => ...)HAVING comparison rendered its constant or closure-captured operand withToString()and appended it to the command text with no quoting, escaping, or parameterization. Because Marten put no quotes around the operand at all, an attacker did not need to break out of a literal — they supplied the entire literal and everything after it.Impact is filter and authorization bypass, and subquery-based disclosure, at the session's database privilege. Numeric operands were never injectable.
Note on impact: Marten executes through
NpgsqlBatch, which refuses multi-statement command text, so stacked-statement modification is not reachable through this sink.Fix: a HAVING operand is now either SQL derived from the document model or a value from the caller's expression, and those are distinct types rather than both being
string. Values always bind as parameters.GHSA-frqq-p5g3-8jq5 — SQL injection via regConfig on the full-text ranking path (critical)
Affects 9.31.0 – 9.38.0. Fixed in 9.39.0.
OrderByTextRank/ThenByTextRankinterpolated the caller-suppliedregConfiginto SQL as a'...'::regconfigliteral with no validation. This is the same class as CVE-2026-45288, returning on a path added after that fix: the validator existed, but as a private member ofFullTextWhereFragment, so the ranking path could not reuse it and did not re-implement it.You are affected only if your application passes untrusted input as the
regConfigargument. It is an optional parameter defaulting toenglish, so most applications never pass it at all.Fix: the check is now a shared validator, applied in
FullTextIndexResolver.ResolveVector— the sink every full-text path funnels through — so present and future callers are covered by construction rather than by remembering. The weighted-index andMarten.PgVectorpaths were folded onto the same validator.Previously fixed, disclosed today
Two advisories for vulnerabilities already fixed in earlier releases are published alongside this one:
Selectprojection. Fixed in 9.15.3.UseTenantPartitionedEvents. Fixed in 9.22.1.If you are on a version older than those, upgrade.
Bug fixes
StreamActionrather than by regex over the PostgreSQL error detail.Id,AggregateTypeand the expected version are now correct regardless of whether Npgsql redacted the detail — which it does unless the connection string carriesInclude Error Detail=true, so this was the common production case. The fallback message no longer passes PostgreSQL's own text through.DisabledTenantExceptioninstead ofUnknownTenantIdException, so an operator who disabled a tenant is no longer told it does not exist. The new type derives fromUnknownTenantIdException, so existingcatchblocks andOnException<T>()policies keep working.GroupJoin/SelectMany, andGROUP BYrendering over a join.Diagnostics and messages
... (truncated)
9.38.0
Eight changes since 9.37.0. Most of this release is silent-wrongness: a permanent sequence gap that stalls the async daemon, telemetry spans attached to the wrong parent, a
DbContextnothing ever disposed, and a vector projection that embedded stale text. Three of them were reported from production by the community.A
VectorProjectiondeclaringMapFromAggregateregistered anything other thanAsyncis now refused when the store is built (#5451, #5468). The class remarks always said Async was required; nothing enforced it, so an Inline registration built without complaint and then embedded text that missed the event that triggered it. Measured: the first save wrote no row at all, because live aggregation reads committed events and the stream had none yet; every later save wrote the state as of the previous event. The content hash recorded that stale text as current and nothing failed.If you have such a registration it will now fail at
DocumentStore.For(...)with a message namingMapFromAggregateandProjectionLifecycle.Async. Event-mapped vector projections registeredInlineare unaffected and remain supported.Event store
A failed batch no longer leaves a permanent gap in the event sequence (#5454, #5456). Under
QuickWithServerTimestamps— the V9 default — aStartStreamtook a per-event INSERT route whoseseq_idcame from an inlinednextval()that nothing read back. The events keptSequence0, and tombstone creation skips exactly those, so any failure later in the same batch (a losingUpdateRevision, a duplicate document INSERT) rolled back with sequence numbers drawn and nothing to fill them. The async daemon's high-water detector then stalled for every tenant in the database until it had seen the gap forStaleSequenceThreshold. AStartStreamnow goes through the samemt_quick_append_eventsfunction an ordinary append already used, which returns its sequence numbers. Reported and fixed by @vpetrevski.mt_quick_append_eventsno longer writes a new stream'smt_streamsrow twice (#5464). It inserted the row with version 0 and then let the trailingUPDATEset the final version — two heap tuples and two WAL records per stream creation, in one transaction, where nothing outside it could observe the intermediate value. This became the default stream-creation path with #5456, so it was worth removing. A one-eventStartStreammeasured 471µs on the old per-event route, 511µs through the function, and 480µs with this change (PostgreSQL 17.10, medians of 3).FetchForWritingagainst a stream that does not exist yet gets the same saving.Projections and read models
DbContextis disposed (#5457, #5466).EfCoreProjectionStorageowns a context built once per tenant per batch, and nothing disposed it on any path —IProjectionStorage<,>declares no disposal contract, so the type that owned it had nothing to hook. Disposal now belongs to the ..._Description has ...
Description has been truncated