litedb-org/LiteDB · error · ArgumentException
Extend expression must return a document
Error message
Extend expression must return a document
What it means
Thrown by UpdateMany when the transform expression passed to it does not evaluate to a BsonDocument for a given source document. UpdateMany treats the transform as an 'extend' operation — it merges the returned document into each existing document — so a scalar/array/null return value has no valid merge semantics. The check happens per-document during the lazy enumeration of the update.
Source
Thrown at LiteDB/Engine/Engine/Update.cs:75
IEnumerable<BsonDocument> transformDocs()
{
var q = new Query { Select = "$", ForUpdate = true };
if (predicate != null)
{
q.Where.Add(predicate);
}
using (var reader = this.Query(collection, q))
{
while (reader.Read())
{
var doc = reader.Current.AsDocument;
var id = doc["_id"];
var value = transform.ExecuteScalar(doc, _header.Pragmas.Collation);
if (!value.IsDocument) throw new ArgumentException("Extend expression must return a document", nameof(transform));
var result = BsonExpressionMethods.EXTEND(doc, value.AsDocument).AsDocument;
// be sure result document will contain same _id as current doc
if (result.TryGetValue("_id", out var newId))
{
if (newId != id) throw LiteException.InvalidUpdateField("_id");
}
else
{
result["_id"] = id;
}
yield return result;
}
}
}
}View on GitHub (pinned to f906a5f850)
Solutions
- Ensure the transform expression always returns a BsonDocument (e.g. "{ count: $.count + 1 }" rather than "$.count + 1").
- If you only need to update a single field, use a document-projection expression that constructs the new sub-document.
- Test the expression in a SELECT first to verify it yields document values for all matched rows.
- Catch ArgumentException from UpdateMany and report which document triggered it.
Example fix
// before — transform returns a scalar
db.Execute("UPDATE items SET { count: $.count + 1 } WHERE $.active = true");
// if expression body is just "$.count + 1" it throws
// after — transform returns a document
// correct SQL/expressions construct a full or partial document:
db.GetCollection("items").UpdateMany("{ count: $.count + 1 }", "$.active = true"); Defensive patterns
Strategy: validation
Validate before calling
// Validate the transform expression returns a document for sample inputs before calling UpdateMany.
public bool TransformReturnsDocument(LiteCollection<BsonDocument> col, BsonExpression transform, BsonExpression predicate)
{
var sample = col.Query().Where(predicate).Limit(1).FirstOrDefault();
if (sample == null) return true; // nothing to check
var value = transform.ExecuteScalar(sample, col.Database.GetCollection("$").Equals /*placeholder*/);
return value.IsDocument;
} Type guard
static bool IsDocumentResult(BsonValue v) => v != null && v.IsDocument;
Try / catch
try
{
col.UpdateMany(transformExpr, predicateExpr);
}
catch (ArgumentException ex) when (ex.Message.Contains("Extend expression must return a document"))
{
throw new InvalidOperationException($"Transform expression '{transformExpr.Source}' returned a non-document value. Rewrite it to return a BsonDocument.", ex);
} Prevention
- Design transform expressions as document literals: '{ field: <expr> }'.
- Test the expression with a SELECT before using it in UpdateMany.
- Avoid bare path/scalar expressions in the transform position.
- Ensure the expression returns a document for every matched row, not just the first.
When it happens
Trigger: Calling engine.UpdateMany(collection, transform, predicate) where the transform BsonExpression evaluates to a non-document BsonValue (e.g. an expression like "$.count + 1" that yields a number, or "$.name" that yields a string) for at least one matched document.
Common situations: Confusing UpdateMany (document transform) with a field-level update; writing an expression that returns different types for different documents; using a path expression that resolves to a scalar.
Related errors
- 0
- GROUP BY expression do not support INCLUDE
- Extend expression must return a document. Eg: `col.UpdateMan
- Extend expression must return an anonymous class to be merge
- Invalid BsonExpression when converted from Linq expression:
AI-assisted analysis of litedb-org/LiteDB@f906a5f850 (2026-08-13).
Data as JSON: /api/errors/3460594c90d980c8.
Report an issue: GitHub.