{"record":{"id":"118e33fd673794a2","repo":"mongodb/node-mongodb-native","slug":"invalid-sort-direction-json-stringify-direction","errorCode":null,"errorMessage":"Invalid sort direction: ${JSON.stringify(direction)}","messagePattern":"Invalid sort direction: (.+?)","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/sort.ts","lineNumber":48,"sourceCode":"\n/** @internal */\ntype SortPairForCmd = [string, SortDirectionForCmd];\n\n/** @internal */\nfunction prepareDirection(direction: any = 1): SortDirectionForCmd {\n  const value = `${direction}`.toLowerCase();\n  if (isMeta(direction)) return direction;\n  switch (value) {\n    case 'ascending':\n    case 'asc':\n    case '1':\n      return 1;\n    case 'descending':\n    case 'desc':\n    case '-1':\n      return -1;\n    default:\n      throw new MongoInvalidArgumentError(`Invalid sort direction: ${JSON.stringify(direction)}`);\n  }\n}\n\n/** @internal */\nfunction isMeta(t: SortDirection): t is { $meta: string } {\n  return typeof t === 'object' && t != null && '$meta' in t && typeof t.$meta === 'string';\n}\n\n/** @internal */\nfunction isPair(t: Sort): t is readonly [string, SortDirection] {\n  if (Array.isArray(t) && t.length === 2) {\n    try {\n      prepareDirection(t[1]);\n      return true;\n    } catch {\n      return false;\n    }\n  }","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/sort.ts#L30-L66","documentation":"Thrown by the internal prepareDirection() helper when a sort direction value cannot be normalized to ascending or descending. The driver accepts 1, -1, 'asc', 'desc', 'ascending', 'descending', or a { $meta: 'textScore' } object; anything else hits the default branch of the switch and raises a MongoInvalidArgumentError. The rejected value is JSON-stringified into the message for debugging.","triggerScenarios":"Calling collection.find().sort({ name: 'up' }) or .sort({ age: 2 }) where the direction is not one of the recognized tokens. Also triggered by .sort([['field', 'sideways']]) or passing a numeric other than 1/-1, e.g. .sort({ x: true }).","commonSituations":"Developers who build sort objects dynamically from user input or query parameters and pass arbitrary strings (e.g. 'up'/'down', 'high'/'low') instead of 'asc'/'desc'. Also occurs when a number like 0 or 2 is used, or when a boolean is mistakenly used as a direction.","solutions":["Ensure every sort direction value is exactly 1, -1, 'asc', 'desc', 'ascending', 'descending', or { $meta: 'textScore' }.","If the direction comes from user input, map it to a valid token before passing it to .sort() (e.g. map 'up'->1, 'down'->-1).","Use a type guard or validation function on the dynamic sort object before calling .sort()."],"exampleFix":"// before\nconst direction = req.query.order; // e.g. 'up'\ncollection.find().sort({ name: direction });\n\n// after\nconst direction = req.query.order === 'desc' ? -1 : 1;\ncollection.find().sort({ name: direction });","handlingStrategy":"validation","validationCode":"const VALID_DIRECTIONS = new Set(['1', '-1', 'asc', 'desc', 'ascending', 'descending']);\nfunction isValidDirection(d: unknown): boolean {\n  if (typeof d === 'object' && d !== null && '$meta' in d && typeof (d as any).$meta === 'string') return true;\n  return typeof d === 'string' && VALID_DIRECTIONS.has(d.toLowerCase()) || d === 1 || d === -1;\n}\nfunction sanitizeSort(sort: Record<string, unknown>): Record<string, 1 | -1> {\n  const out: Record<string, 1 | -1> = {};\n  for (const [k, v] of Object.entries(sort)) {\n    if (isValidDirection(v)) out[k] = (String(v).match(/^(1|asc|ascending)$/i) ? 1 : -1);\n  }\n  return out;\n}","typeGuard":"import type { SortDirection } from 'mongodb';\nfunction isSortDirection(v: unknown): v is SortDirection {\n  if (v === 1 || v === -1) return true;\n  if (typeof v === 'string') return ['asc','desc','ascending','descending'].includes(v.toLowerCase());\n  if (typeof v === 'object' && v !== null && '$meta' in v && typeof (v as any).$meta === 'string') return true;\n  return false;\n}","tryCatchPattern":"try {\n  await collection.find().sort(sortSpec).toArray();\n} catch (e) {\n  if (e instanceof MongoInvalidArgumentError && /Invalid sort direction/.test(e.message)) {\n    // fall back to a safe default sort\n    await collection.find().sort({ _id: 1 }).toArray();\n  } else throw e;\n}","preventionTips":["Whitelist and map user-provided sort tokens (e.g. 'up'/'down') to 1/-1 before passing to .sort().","Use TypeScript's SortDirection type on dynamic sort builders to catch invalid values at compile time.","Unit-test sort construction with representative user inputs."],"tags":["sort","query","validation","crud"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}