OrchardCMS/OrchardCore · error · InvalidOperationException
An ambiguous index has been found.
Error message
An ambiguous index has been found.
What it means
When building the ContentItems GraphQL query, aliases collected for the same index (same Index key) must agree on IndexType. If two aliased paths map to the same index name but different index types, the query would produce contradictory table bindings, so an InvalidOperationException('An ambiguous index has been found.') is thrown in FilterWhereArgumentsAsync.
Solutions
- Rename one of the conflicting indexes so each index name maps to exactly one index type.
- Change the GraphQL query to use a single alias/path for that index.
- Align the IndexType of the duplicated profiles in the indexing settings.
Example fix
// before // two profiles: "BlogPostIndex" (type Sql) and "BlogPostIndex" (type Lucene) // after // rename one to "BlogPostSqlIndex" or remove the duplicate profile
Defensive patterns
Strategy: validation
Validate before calling
// pre-check before building the query: ensure each index name maps to one index type
var dupes = aliases.GroupBy(a => a.Index).Where(g => g.Select(x => x.IndexType).Distinct().Count() > 1).ToList();
if (dupes.Any()) throw new InvalidOperationException($"Ambiguous indexes: {string.Join(",", dupes.Select(d => d.Key))}"); Try / catch
try { var result = await query.FilterWhereArgumentsAsync(...); }
catch (InvalidOperationException ex) when (ex.Message == "An ambiguous index has been found.") { _logger.LogError(ex, "Duplicate index name with differing index types in GraphQL where-input"); throw; } Prevention
- Keep index profile names unique across providers and modules.
- Review custom index handlers for name collisions.
- Document index ownership per module to avoid cross-module clashes.
When it happens
Trigger: A GraphQL where-input uses two aliased paths (e.g. two fields or two index profiles) whose resolved alias.Index is identical but whose IndexType differs — typically two index profiles with the same index name configured with different index types (SQL vs Lucene, or different profile types).
Common situations: Two ContentIndex profiles named the same for different providers; custom index handlers emitting colliding index names; merging where-clauses across modules that both register aliases for the same index name.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Missing table alias for path
- The index does not have a key field.
- Index mappings cannot be null.
- There is already another index with the same name.
- Both the index-name and index full-name must be set.
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/c5265f3a79835fc5.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs:163
predicateQuery.CreateTableAlias(nameof(ContentItemIndex), defaultTableAlias);
// Add all provided table alias to the current predicate query.
var providers = fieldContext.RequestServices.GetServices<IIndexAliasProvider>();
var indexes = new Dictionary<string, IndexAlias>(StringComparer.OrdinalIgnoreCase);
var indexAliases = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var aliasProvider in providers)
{
foreach (var alias in await aliasProvider.GetAliasesAsync())
{
predicateQuery.CreateAlias(alias.Alias, alias.Index, alias.IsPartial);
if (indexAliases.Add(alias.Alias))
{
if (!indexes.TryAdd(alias.Index, alias))
{
if (indexes[alias.Index].IndexType != alias.IndexType)
{
throw new InvalidOperationException("An ambiguous index has been found.");
}
}
}
}
}
var expressions = Expression.Conjunction();
var whereInput = (IFilterInputObjectGraphType)fieldContext.FieldDefinition.Arguments.FirstOrDefault(x => x.Name == "where")?.ResolvedType;
BuildWhereExpressions(where, expressions, null, whereInput, indexAliases);
expressions.SearchUsedAlias(predicateQuery);
// Add all Indexes that were used in the predicate query.
IQuery<ContentItem> contentQuery = query;
foreach (var usedAlias in predicateQuery.GetUsedAliases())
{View on GitHub (pinned to 4306c0717f)