{"record":{"id":"6328bdd25f4005c6","repo":"sinelaw/fresh","slug":"tour-could-not-resolve-lines-step-lines-0-step-lines-1-in","errorCode":null,"errorMessage":"Tour: could not resolve lines ${step.lines[0]}-${step.lines[1]} in ${step.file_path}","messagePattern":"Tour: could not resolve lines (.+?)-(.+?) in (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/fresh-editor/plugins/code-tour.ts","lineNumber":600,"sourceCode":"  return 0;\n}\n\nfunction clearTourOverlays(t: TourInstance): void {\n  for (const bufferId of t.paintedBuffers) {\n    editor.clearNamespace(bufferId, t.namespace);\n  }\n  t.paintedBuffers.clear();\n}\n\nasync function paintStepOverlay(t: TourInstance): Promise<void> {\n  const step = currentStep(t);\n  const bufferId = stepBufferId(resolveStepPath(t.manifestPath, step.file_path));\n  if (!bufferId) return;\n\n  clearTourOverlays(t);\n  const range = await lineRangeBytes(bufferId, step.lines[0], step.lines[1]);\n  if (!range) {\n    editor.warn(\n      `Tour: could not resolve lines ${step.lines[0]}-${step.lines[1]} in ${step.file_path}`,\n    );\n    return;\n  }\n  // One range-wide overlay; the host tail-fills every row it spans, so\n  // each line paints a full-width band — a region marker visually\n  // distinct from a text selection (which never covers the empty tail\n  // of a line). The bg is a theme key so the band restyles with the\n  // theme, like every other tour colour. It is the band's *own* key:\n  // the occurrence highlight next door is tuned for a few cells of text\n  // that must stay legible and stay apart from the selection, which is\n  // the wrong trade for a wash over whole line ranges.\n  editor.addOverlay(bufferId, t.namespace, range[0], range[1], {\n    bg: \"ui.tour_step_bg\",\n    extendToLineEnd: true,\n  });\n  t.paintedBuffers.add(bufferId);\n}","sourceCodeStart":582,"sourceCodeEnd":618,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/plugins/code-tour.ts#L582-L618","documentation":"In the code-tour plugin, paintStepOverlay resolves the step's target file to a buffer and asks the host for the byte range covering step.lines[0]..step.lines[1]; if lineRangeBytes returns null the lines cannot be resolved (file shorter than requested, or buffer content changed) and this warning is emitted instead of painting the overlay. The tour step is skipped visually but the tour continues.","triggerScenarios":"revealStep -> paintStepOverlay on a step whose lines[0]/lines[1] exceed the target buffer's current line count, the target file's buffer could not load those lines, or the file was edited/truncated since the tour was authored.","commonSituations":"Sharing a tour whose target file differs between machines (different branch/commit); target file refactored so highlighted lines no longer exist; typos in the step's file_path or 1-based line numbers past EOF.","solutions":["Update the step's lines to a range that exists in the current version of step.file_path.","Verify step.file_path resolves correctly relative to the tour manifest (resolveStepPath).","Re-generate the tour against the current commit, or pin the tour to a matching revision of the target file.","Open the target file and confirm its line count covers lines[0]-lines[1]."],"exampleFix":"// before (tour step)\n{ \"file_path\": \"src/app.ts\", \"lines\": [120, 140] } // file has 100 lines\n// after\n{ \"file_path\": \"src/app.ts\", \"lines\": [10, 24] }","handlingStrategy":"validation","validationCode":"const content = fs.readFileSync(resolveStepPath(manifestPath, step.file_path), 'utf8');\nconst lineCount = content.split('\\n').length;\nif (step.lines[0] < 1 || step.lines[1] >= lineCount) {\n  throw new Error(`step lines ${step.lines[0]}-${step.lines[1]} exceed ${step.file_path} (${lineCount} lines)`);\n}","typeGuard":"function linesInRange(step, totalLines) { return Array.isArray(step.lines) && step.lines.length === 2 && step.lines[0] >= 1 && step.lines[1] < totalLines; }","tryCatchPattern":"try { await revealStep(tour, i); } catch (e) { if (e.message.includes('could not resolve lines')) editor.warn(`skipping step ${i}: target moved`); else throw e; }","preventionTips":["Regenerate tours whenever the target files change; avoid hand-editing line numbers.","Use anchors/symbols instead of raw line numbers when authoring tours.","Validate all step line ranges against the current tree in CI.","Keep tour manifests in the same repo/commit as their target files."],"tags":["tours","overlay","line-range","plugin"],"backgroundTag":"index-out-of-range","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}