mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Invalid sort format: Sort must be a valid object
Error message
Invalid sort format: ${JSON.stringify(sort)} Sort must be a valid object What it means
Thrown by formatSort() when the sort argument is not null/undefined, not a string, and not an object. The Sort type union expects a string, array, Map, or plain object; a primitive like a number or boolean fails the typeof checks and raises a MongoInvalidArgumentError. The invalid value is JSON-stringified in the message.
Solutions
- Pass a valid Sort shape: an object like { field: 1 }, an array like [['field', 1]], a Map, or a string field name.
- If the sort value is dynamic, validate it is a string or object before calling .sort().
- Remove `any` typing on the sort variable so TypeScript flags the misuse at compile time.
Example fix
// before
const sort = config.sortValue; // number 42
collection.find().sort(sort);
// after
const sort = config.sortValue ?? {};
collection.find().sort(typeof sort === 'object' ? sort : { _id: 1 }); Defensive patterns
Strategy: type-guard
Validate before calling
function isSortable(v: unknown): v is string | object {
return v == null || typeof v === 'string' || typeof v === 'object';
}
const safeSort = isSortable(userSort) ? userSort : undefined; Type guard
function isSortInput(v: unknown): v is string | Record<string, unknown> | unknown[] | Map<string, unknown> {
return v == null || typeof v === 'string' || (typeof v === 'object' && !Array.isArray(v) || Array.isArray(v));
} Try / catch
try {
await collection.find().sort(sortValue as any).toArray();
} catch (e) {
if (e instanceof MongoInvalidArgumentError && /Invalid sort format/.test(e.message)) {
await collection.find().toArray(); // no sort
} else throw e;
} Prevention
- Avoid `any` typing on sort variables so TypeScript enforces the Sort union at compile time.
- Validate dynamically-built sort values are objects/arrays/strings before calling .sort().
- Default to undefined when the sort input is of an unexpected type.
When it happens
Trigger: Calling .sort(42), .sort(true), or .sort(NaN) directly. Also reachable when a variable typed loosely (any) holds a primitive and is passed as the sort argument without prior validation.
Common situations: Code that constructs sort parameters dynamically and accidentally passes a scalar (e.g. a parsed numeric from config) instead of an object. TypeScript users typically catch this at compile time, so runtime hits occur in JS codebases or when using `any`.
Related errors
- Invalid sort direction
- Document must be a valid JavaScript object
- Selector must be a valid JavaScript object
- Update operations require that all atomic operators have…
- All values of tls/ssl must be the same.
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/c0110101d077b9cd.
Report an issue: GitHub.
Appendix: source
Thrown at src/sort.ts:127
function mapToMap(t: ReadonlyMap<string, SortDirection>): SortForCmd {
const sortEntries: SortPairForCmd[] = Array.from(t).map(([k, v]) => [
`${k}`,
prepareDirection(v)
]);
return new Map(sortEntries);
}
/** converts a Sort type into a type that is valid for the server (SortForCmd) */
export function formatSort(
sort: Sort | undefined,
direction?: SortDirection
): SortForCmd | undefined {
if (sort == null) return undefined;
if (typeof sort === 'string') return new Map([[sort, prepareDirection(direction)]]); // 'fieldName'
if (typeof sort !== 'object') {
throw new MongoInvalidArgumentError(
`Invalid sort format: ${JSON.stringify(sort)} Sort must be a valid object`
);
}
if (!isReadonlyArray(sort)) {
if (isMap(sort)) return mapToMap(sort); // Map<fieldName, SortDirection>
if (Object.keys(sort).length) return objectToMap(sort); // { [fieldName: string]: SortDirection }
return undefined;
}
if (!sort.length) return undefined;
if (isDeep(sort)) return deepToMap(sort); // [ [fieldName, sortDir], [fieldName, sortDir] ... ]
if (isPair(sort)) return pairToMap(sort); // [ fieldName, sortDir ]
return stringsToMap(sort); // [ fieldName, fieldName ]
}
View on GitHub (pinned to dce7939f86)