{"id":"90e63c16be911a45","repo":"vitest-dev/vitest","slug":"offset-is-longer-than-source-length-offset-offs","errorCode":null,"errorMessage":"offset is longer than source length! offset ${offset} > length ${source.length}","messagePattern":"offset is longer than source length! offset (.+?) > length (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/utils/src/offset.ts","lineNumber":25,"sourceCode":"): number {\n  const lines = source.split(lineSplitRE)\n  const nl = /\\r\\n/.test(source) ? 2 : 1\n  let start = 0\n\n  if (lineNumber > lines.length) {\n    return source.length\n  }\n\n  for (let i = 0; i < lineNumber - 1; i++) {\n    start += lines[i].length + nl\n  }\n\n  return start + columnNumber\n}\n\nexport function offsetToLineNumber(source: string, offset: number): number {\n  if (offset > source.length) {\n    throw new Error(\n      `offset is longer than source length! offset ${offset} > length ${source.length}`,\n    )\n  }\n  const lines = source.split(lineSplitRE)\n  const nl = /\\r\\n/.test(source) ? 2 : 1\n  let counted = 0\n  let line = 0\n  for (; line < lines.length; line++) {\n    const lineLength = lines[line].length + nl\n    if (counted + lineLength >= offset) {\n      break\n    }\n\n    counted += lineLength\n  }\n  return line + 1\n}\n","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/utils/src/offset.ts#L7-L43","documentation":"Thrown by offsetToLineNumber() in packages/utils/src/offset.ts when the requested character offset exceeds the source string length. offsetToLineNumber is used to map a character index back to a 1-based line number for diagnostics, inline snapshot placement, and stack-trace rendering. An out-of-range offset means the caller computed the offset against a different (longer) version of the source than the one passed in — typically a stale cache or a transform mismatch.","triggerScenarios":"Source-map or inline-snapshot code computes an offset from the transformed code but passes the original (shorter) source; a custom SnapshotEnvironment returns a different file content on consecutive reads; instrumentation that mutates the source between offset calculation and line lookup.","commonSituations":"Source-map mismatches after a Vite/Rollup upgrade; cache invalidation issues (.vite cache stale); concurrent edits during watch mode; custom transformers that change file length without updating the source map.","solutions":["Clear Vitest/Vite caches (rm -rf node_modules/.vite node_modules/.vitest) and re-run.","Ensure the source string passed to offsetToLineNumber is the same artifact used to compute the offset.","If implementing a custom SnapshotEnvironment or transformer, guarantee readSnapshotFile returns stable content.","Update @vitest/utils and vitest to matching versions; mismatched versions across the monorepo cause this."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function assertOffsetInRange(source: string, offset: number): void {\n  if (offset > source.length) {\n    throw new RangeError(`offset ${offset} exceeds source length ${source.length}`)\n  }\n}","typeGuard":"const offsetInRange = (source: string, offset: number): boolean =>\n  offset >= 0 && offset <= source.length","tryCatchPattern":null,"preventionTips":["Always compute offsets and call offsetToLineNumber with the same source string instance.","Clear node_modules/.vite and node_modules/.vitest after upgrades to avoid stale caches.","Keep @vitest/utils and vitest on matching versions across the monorepo."],"tags":["utils","offset","source-maps","cache"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}