abpframework/abp · error · AbpValidationException
Sorting expression is not supported.
Error message
Sorting expression is not supported.
What it means
AbpDynamicSortingGuard installs an ExpressionVisitor (via ExtensibilityPoint.QueryOptimizer) that inspects every OrderBy/ThenBy selector built from a user-supplied sorting string and rejects anything that is not plain property/field access or a constant-string indexer (it["Prop"]). In PropertyOnlySelectorVisitor.VisitMethodCall, after the IsConstantStringIndexer allowance, any remaining method call inside the sort-key lambda throws AbpValidationException ('Sorting expression is not supported.'). This is a security guard: it prevents method invocation, function calls, and arbitrary computation from being smuggled through a dynamic sorting string.
Source
Thrown at framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbpDynamicSortingGuard.cs:107
protected override Expression VisitMethodCall(MethodCallExpression node)
{
// Allow property-bag / shadow-property access through a constant string
// indexer (it["Prop"], Data["Prop"], mainEntity["Prop"], ...). The
// constant key cannot smuggle in an arbitrary method invocation, so this
// does not widen the injection surface the guard protects against; it
// treats the indexer access like ordinary property access.
if (IsConstantStringIndexer(node))
{
if (node.Object != null)
{
Visit(node.Object);
}
return node;
}
throw new AbpValidationException(Message);
}
protected override Expression VisitBinary(BinaryExpression node)
=> throw new AbpValidationException(Message);
protected override Expression VisitConditional(ConditionalExpression node)
=> throw new AbpValidationException(Message);
protected override Expression VisitConstant(ConstantExpression node)
=> throw new AbpValidationException(Message);
private static bool IsConstantStringIndexer(MethodCallExpression node)
{
// Must be an instance call with a single constant string argument.
if (node.Object == null
|| node.Arguments.Count != 1
|| node.Arguments[0] is not ConstantExpression { Value: string })
{View on GitHub (pinned to 7ed43b1931)
Solutions
- Restrict the sorting string to bare property/field names (e.g. 'Name', 'Age desc') and drop any method-call syntax.
- Maintain a server-side whitelist of allowed sortable properties and validate the incoming sorting string against it before applying.
- Map computed/display needs to a real projected property (Select into a DTO) and sort by that property name instead of invoking a method in the sort key.
- For shadow/property-bag access, use the constant-string indexer form it["Prop"] which the guard explicitly allows.
Example fix
// before: method call in the sort string -> AbpValidationException at :107
var list = await repo.GetListAsync(sorting: "Name.ToUpper()");
// after: sort by a plain property name (optionally with direction)
var list = await repo.GetListAsync(sorting: "Name");
// or, for a computed need, project first then sort by the projected property
var dto = query.Select(x => new { x.Id, Upper = x.Name.ToUpper() })
.OrderBy("Upper"); Defensive patterns
Strategy: validation
Validate before calling
static readonly HashSet<string> SortableProperties = new(StringComparer.OrdinalIgnoreCase)
{
"Name", "Age", "CreatedOn", "Id"
};
static string? SanitizeSorting(string? sorting)
{
if (sorting.IsNullOrWhiteSpace()) return null;
var parts = sorting.Split(',');
var accepted = new List<string>();
foreach (var raw in parts)
{
var token = raw.Trim();
var descending = token.EndsWith(" desc", StringComparison.OrdinalIgnoreCase);
var name = token.Substring(0, token.Length - (descending ? 5 : 0)).Trim();
if (!SortableProperties.Contains(name))
{
throw new ArgumentException($"Sorting property is not allowed: {name}");
}
accepted.Add(descending ? $"{name} desc" : name);
}
return string.Join(", ", accepted);
}
// usage:
query = query.OrderBy(SanitizeSorting(inputSorting)); Try / catch
try
{
result = await appService.GetListAsync(new PagedAndSortedResultRequestDto { Sorting = sorting });
}
catch (Volo.Abp.Validation.AbpValidationException ex) when (ex.Message.Contains("Sorting expression is not supported"))
{
// surface a 400-friendly error to the client; never echo the raw sorting back unescaped
throw new UserFriendlyException("Sorting is limited to allowed property names.");
} Prevention
- Never pass raw client sorting straight to a query; always validate against a property whitelist.
- For computed/display columns, project them into DTO properties and whitelist those names.
- Reject sorting strings containing '(', ')', or method-call syntax at the API boundary.
- Keep the guard installed (it is on by default) — it is a security control against expression injection.
When it happens
Trigger: Applying a dynamic sort whose parsed selector contains a method call that is not a string-keyed indexer with a constant argument. With System.Linq.Dynamic.Core this happens for inputs like "Name.ToUpper()", "x.Substring(0,3)", "Guid()", or any function-style token in the sorting string passed to a paged/result query that the guard then visits. The throw originates at AbpDynamicSortingGuard.cs:107.
Common situations: Passing raw user input as the sorting parameter to an application service query; front-end sending computed display expressions instead of raw property names; sorting strings that try to call formatting or conversion methods; a DTO with a computed property that the client references through a method rather than a mapped property.
Related errors
- Invalid npm package name detected: {SanitizeForLog(packageNa
- Invalid npm package version detected: {SanitizeForLog(versio
- Project name cannot contain ".."! Specify a different name.
- Expected Dapr App API Token is not provided! Dapr should set
- The Dapr App API Token (provided in the 'dapr-api-token' HTT
AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13).
Data as JSON: /api/errors/db54252b8996d371.
Report an issue: GitHub.