{"record":{"id":"4f5a099821f04592","repo":"mongodb/node-mongodb-native","slug":"stream-end-options-end-must-not-be-negative","errorCode":null,"errorMessage":"Stream end (${options.end}) must not be negative","messagePattern":"Stream end \\((.+?)\\) must not be negative","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/gridfs/download.ts","lineNumber":471,"sourceCode":"    return options.start - stream.s.bytesRead;\n  }\n  throw new MongoInvalidArgumentError('Start option must be defined');\n}\n\nfunction handleEndOption(\n  stream: GridFSBucketReadStream,\n  doc: Document,\n  cursor: FindCursor<GridFSChunk>,\n  options: GridFSBucketReadStreamOptions\n) {\n  if (options && options.end != null) {\n    if (options.end > doc.length) {\n      throw new MongoInvalidArgumentError(\n        `Stream end (${options.end}) must not be more than the length of the file (${doc.length})`\n      );\n    }\n    if (options.start == null || options.start < 0) {\n      throw new MongoInvalidArgumentError(`Stream end (${options.end}) must not be negative`);\n    }\n\n    const start = options.start != null ? Math.floor(options.start / doc.chunkSize) : 0;\n\n    cursor.limit(Math.ceil(options.end / doc.chunkSize) - start);\n\n    stream.s.expectedEnd = Math.ceil(options.end / doc.chunkSize);\n\n    return Math.ceil(options.end / doc.chunkSize) * doc.chunkSize - options.end;\n  }\n  throw new MongoInvalidArgumentError('End option must be defined');\n}\n","sourceCodeStart":453,"sourceCodeEnd":484,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/gridfs/download.ts#L453-L484","documentation":"handleEndOption (src/gridfs/download.ts:470) throws MongoInvalidArgumentError when end is provided but start is null or negative. The message text says 'must not be negative' but the actual guard rejects a missing/invalid start in conjunction with an end value, because a valid range requires a valid start.","triggerScenarios":"Calling openDownloadStream(id, { end: N }) with no start, or with start < 0. Internally, handleEndOption requires options.start to be a non-negative number when end is set.","commonSituations":"Passing only an end offset assuming start defaults to 0 internally (it does not in this code path). Mixing negative start with a positive end.","solutions":["Always provide a non-negative start when supplying end: openDownloadStream(id, { start: 0, end: N }).","Validate that start is a non-negative integer whenever end is set."],"exampleFix":"// before\nconst s = bucket.openDownloadStream(id, { end: 1000 });\n// after\nconst s = bucket.openDownloadStream(id, { start: 0, end: 1000 });","handlingStrategy":"validation","validationCode":"function normalizeEndRange(range) {\n  if (range?.end != null) {\n    range.start = Math.max(0, range.start ?? 0);\n  }\n  return range;\n}","typeGuard":"function hasValidStartForEnd(range: any): boolean {\n  return range?.end == null || (typeof range.start === 'number' && range.start >= 0);\n}","tryCatchPattern":"try {\n  bucket.openDownloadStream(id, { end });\n} catch (e) {\n  if (e instanceof MongoInvalidArgumentError && /must not be negative/.test(e.message)) {\n    // add start: 0\n  }\n}","preventionTips":["Always pass start: 0 (or a valid non-negative start) whenever you pass end.","Build range objects through one helper that guarantees start is set.","Document that end requires an accompanying start in your wrapper API."],"tags":["gridfs","stream","validation","range"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}