OrchardCMS/OrchardCore · error · InvalidOperationException

Index mappings cannot be null.

Error message

Index mappings cannot be null.

What it means

ElasticsearchIndexManager builds a CreateIndexRequest from an index profile's stored metadata. The metadata.IndexMappings value is mandatory — it defines the Elasticsearch mappings for the index. When it is null the manager cannot construct a valid create-index request and throws.

Solutions

  1. Re-create the index from the admin UI so metadata.IndexMappings is regenerated by the index handler
  2. Ensure your IContentItemIndexHandler / mapping description actually populates IndexMappings before creating the index
  3. Delete the stale index profile metadata and rebuild: Features > Elasticsearch > rebuild the index
  4. Inspect the stored metadata document (ElasticsearchDocumentStorage) and fix/restore the IndexMappings value

Example fix

// before
metadata.IndexMappings = null; // handler never set mappings
// after
var builder = new ContentItemIndexBuilder(typeOptions, _logger);
await DescribeMappingsAsync(builder); // ensures IndexMappings populated before CreateIndexAsync
Defensive patterns

Strategy: validation

Validate before calling

var metadata = await _indexStore.SearchAsync<ElasticsearchIndexMetadata>(m => m.IndexName == indexProfile.IndexName);
if (metadata?.IndexMappings is null) throw new InvalidOperationException($"Index '{indexProfile.IndexName}' has no mappings; rebuild the index first");

Type guard

bool HasMappings(ElasticsearchIndexMetadata m) => m?.IndexMappings?.Mapping != null;

Try / catch

try { await indexManager.CreateAsync(indexProfile); } catch (InvalidOperationException ex) when (ex.Message.Contains("Index mappings cannot be null")) { // trigger full re-index await _indexingService.RebuildIndexAsync(indexProfile.IndexName); }

Prevention

When it happens

Trigger: Calling createIndexRequest/GetCreateIndexRequest for an Elasticsearch index profile whose IndexMappings was never persisted (e.g. the index handler never populated mappings, metadata was partially saved, or the index was created before the mappings step ran).

Common situations: Interrupted indexing that saved metadata without mappings; manually edited index metadata documents; upgrading indexes created by older module versions that lacked the IndexMappings field; custom Elasticsearch index handlers that do not call the mapping description.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/e597c0944b3270a8. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore/OrchardCore.Elasticsearch.Core/Services/ElasticsearchIndexManager.cs:468

                    !s_tokenFilterGetter.TryGetValue(typeObject.ToString(), out var tokenFilterType))
                {
                    continue;
                }

                RemoveTypeNode(filter.Value);

                var tokenFilter = filter.Value.ToObject(tokenFilterType) as ITokenFilter;

                if (tokenFilter is not null)
                {
                    indexSettings.Analysis.TokenFilters.Add(filter.Key, tokenFilter);
                }
            }
        }

        if (metadata.IndexMappings is null)
        {
            throw new InvalidOperationException("Index mappings cannot be null.");
        }

        var createIndexRequest = new CreateIndexRequest(indexProfile.IndexFullName)
        {
            Settings = indexSettings,
            Mappings = metadata.IndexMappings.Mapping ?? new TypeMapping(),
        };

        // Custom metadata to store the last indexing task id.
        createIndexRequest.Mappings.Meta ??= new FluentDictionary<string, object>();

        createIndexRequest.Mappings.Meta[ElasticsearchConstants.LastTaskIdMetadataKey] = 0;

        return createIndexRequest;
    }

    private static IAnalyzer GetAnalyzer(JsonObject analyzerProperties)
    {

View on GitHub (pinned to 4306c0717f)