litedb-org/LiteDB · error · LiteException

0

0

Error message

Multikey index expression do not support unique option

What it means

Thrown by EnsureIndex when the index expression is non-scalar (multikey, i.e., can produce multiple index entries per document, like an array path) AND the unique flag is set to true. Unique indexes require exactly one key per document, so multikey expressions are incompatible with uniqueness. This is a LiteException (code 0) thrown at validation time before any index is created.

Source

Thrown at LiteDB/Engine/Engine/Index.cs:25

namespace LiteDB.Engine
{
    public partial class LiteEngine
    {
        /// <summary>
        /// Create a new index (or do nothing if already exists) to a collection/field
        /// </summary>
        public bool EnsureIndex(string collection, string name, BsonExpression expression, bool unique)
        {
            if (collection.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(collection));
            if (name.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(name));
            if (expression == null) throw new ArgumentNullException(nameof(expression));
            if (expression.IsIndexable == false) throw new ArgumentException("Index expressions must contains at least one document field. Used methods must be immutable. Parameters are not supported.", nameof(expression));

            if (name.Length > INDEX_NAME_MAX_LENGTH) throw LiteException.InvalidIndexName(name, collection, "MaxLength = " + INDEX_NAME_MAX_LENGTH);
            if (!name.IsWord()) throw LiteException.InvalidIndexName(name, collection, "Use only [a-Z$_]");
            if (name.StartsWith("$")) throw LiteException.InvalidIndexName(name, collection, "Index name can't start with `$`");
            if (expression.IsScalar == false && unique) throw new LiteException(0, "Multikey index expression do not support unique option");

            if (expression.Source == "$._id") return false; // always exists

            return this.AutoTransaction(transaction =>
            {
                var snapshot = transaction.CreateSnapshot(LockMode.Write, collection, true);
                var collectionPage = snapshot.CollectionPage;
                var indexer = new IndexService(snapshot, _header.Pragmas.Collation, _disk.MAX_ITEMS_COUNT);
                var data = new DataService(snapshot, _disk.MAX_ITEMS_COUNT);

                // check if index already exists
                var current = collectionPage.GetCollectionIndex(name);

                // if already exists, just exit
                if (current != null)
                {
                    // but if expression are different, throw error
                    if (current.Expression != expression.Source) throw LiteException.IndexAlreadyExist(name);

View on GitHub (pinned to f906a5f850)

Solutions

  1. Set unique=false for multikey/array expressions.
  2. Change the expression to a scalar field if uniqueness is truly required, e.g., index a single-value field instead of an array.
  3. Check `expression.IsScalar` before passing unique=true to EnsureIndex.

Example fix

// before
col.EnsureIndex("idx_tags", "$.tags", unique: true);
// after
col.EnsureIndex("idx_tags", "$.tags", unique: false);
Defensive patterns

Strategy: validation

Validate before calling

if (unique && !expression.IsScalar)
    throw new InvalidOperationException("Cannot create a unique index on a multikey expression.");
col.EnsureIndex(name, expression, unique);

Type guard

static bool CanBeUniqueIndex(BsonExpression expr, bool unique) => !unique || expr.IsScalar;

Try / catch

try { col.EnsureIndex(name, expr, unique: true); }
catch (LiteException ex) when (ex.Message.Contains("do not support unique option"))
{ /* set unique=false or use a scalar expression */ }

Prevention

When it happens

Trigger: Calling `EnsureIndex(collection, name, "$.tags", unique: true)` where $.tags is an array field. Any non-scalar expression (containing [*], MAP, etc.) passed with unique=true.

Common situations: Attempting to enforce uniqueness on an array field. Copying index definitions from a schema where an array field was mistakenly marked unique. Programmatically generating indexes without checking expression scalar-ness against the unique flag.

Related errors


AI-assisted analysis of litedb-org/LiteDB@f906a5f850 (2026-08-13). Data as JSON: /api/errors/c56b3c6418093e39. Report an issue: GitHub.