You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Exception when used locally in 4.0.0. Kestrel related? #401
I have verified that I am running the latest version of ImageSharp.Web
I have verified if the problem exist in both DEBUG and RELEASE mode
I have searched open and closed issues to ensure it has not already been reported
ImageSharp.Web version
4.0.0
Other Six Labors packages and versions
ImageSharp 4.0.0
Environment (Operating system, version and so on)
Windows 11, Kestrel
.NET version
10.0
Description
Since 4.0.0, when running ImageSharp.Web locally or in the CI/CD pipelines the following exception is thrown intermittently. On our production system (Azure App Service, Windows) it is not thrown at all.
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HNM646UV6KOA", Request id "0HNM646UV6KOA:00000017": An unhandled exception was thrown by the application.
System.ArgumentException: An item with the same key has already been added. Key: autoorient
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at System.Collections.ObjectModel.KeyedCollection`2.AddKey(TKey key, TItem item)
at System.Collections.ObjectModel.KeyedCollection`2.InsertItem(Int32 index, TItem item)
at System.Collections.ObjectModel.Collection`1.Insert(Int32 index, T item)
at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddlewareOptions.<>c.<.ctor>b__56_1(ImageCommandContext context)
at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext httpContext, Boolean retry)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
Based on the stacktrace, it seems like the following line is causing the issue:
Are you using a custom IRequestParser, custom OnParseCommandsAsync, or any middleware that branches/re-executes the pipeline for image requests?
The default parser creates a new CommandCollection per request, and normal ASP.NET Core middleware execution should be sequential for a single request. The exception implies that the CommandCollection changed between Contains("autoorient") and Insert(...), or that the same collection/context is being reused or mutated concurrently. HttpContext itself is not thread-safe, but this does not by itself suggest Kestrel is invoking our middleware concurrently for the same request.
Based on your reply I investigated further and I think I found the issue. In our code we use the PresetOnlyQueryCollectionRequestParser that I contributed. I looked at its code and found this:
I tested my theory by copying the PresetOnlyQueryCollectionRequestParser and adjusting the code to:
if(requestedPresetis not null&&presets.TryGetValue(requestedPreset,outvarcollection)){CommandCollectioncopy=[];// I didn't see a better way to create a copy, so I used a loopforeach(varpairincollection)copy.Add(pair.Key,pair.Value!);returncopy;}
Activity
[-]Exception when used locally[/-][+]Exception when used locally in 4.0.0[/+][-]Exception when used locally in 4.0.0[/-][+]Exception when used locally in 4.0.0. Kestrel related?[/+]JimBobSquarePants commentedon Jun 11, 2026
Are you using a custom
IRequestParser, customOnParseCommandsAsync, or any middleware that branches/re-executes the pipeline for image requests?The default parser creates a new
CommandCollectionper request, and normal ASP.NET Core middleware execution should be sequential for a single request. The exception implies that theCommandCollectionchanged betweenContains("autoorient")andInsert(...), or that the same collection/context is being reused or mutated concurrently.HttpContextitself is not thread-safe, but this does not by itself suggest Kestrel is invoking our middleware concurrently for the same request.marklagendijk commentedon Jun 11, 2026
Very good analysis and description!
Based on your reply I investigated further and I think I found the issue. In our code we use the
PresetOnlyQueryCollectionRequestParserthat I contributed. I looked at its code and found this:ImageSharp.Web/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs
Line 44 in 592083f
PresetOnlyQueryCollectionRequestParserparses the presets from configuration, into aDictionary<string, CommandCollection>ParseRequestCommandsit returns the matchedCommandCollectionfrom thatDictionary.CommandCollectionis shared among different requests that use the same preset.CommandCollection.marklagendijk commentedon Jun 11, 2026
I tested my theory by copying the
PresetOnlyQueryCollectionRequestParserand adjusting the code to:This indeed fixes the issue!
JimBobSquarePants commentedon Jun 11, 2026
I think we should create a
DeepClonemethod.marklagendijk commentedon Jun 11, 2026
Makes sense.
Btw, I'm currently not able to contribute a PR for this issue.