sinelaw/fresh · warning

Tour: could not resolve lines

Error message

Tour: could not resolve lines ${step.lines[0]}-${step.lines[1]} in ${step.file_path}

What it means

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.

Solutions

  1. Update the step's lines to a range that exists in the current version of step.file_path.
  2. Verify step.file_path resolves correctly relative to the tour manifest (resolveStepPath).
  3. Re-generate the tour against the current commit, or pin the tour to a matching revision of the target file.
  4. Open the target file and confirm its line count covers lines[0]-lines[1].

Example fix

// before (tour step)
{ "file_path": "src/app.ts", "lines": [120, 140] } // file has 100 lines
// after
{ "file_path": "src/app.ts", "lines": [10, 24] }
Defensive patterns

Strategy: validation

Validate before calling

const content = fs.readFileSync(resolveStepPath(manifestPath, step.file_path), 'utf8');
const lineCount = content.split('\n').length;
if (step.lines[0] < 1 || step.lines[1] >= lineCount) {
  throw new Error(`step lines ${step.lines[0]}-${step.lines[1]} exceed ${step.file_path} (${lineCount} lines)`);
}

Type guard

function linesInRange(step, totalLines) { return Array.isArray(step.lines) && step.lines.length === 2 && step.lines[0] >= 1 && step.lines[1] < totalLines; }

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/6328bdd25f4005c6. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/plugins/code-tour.ts:600

  return 0;
}

function clearTourOverlays(t: TourInstance): void {
  for (const bufferId of t.paintedBuffers) {
    editor.clearNamespace(bufferId, t.namespace);
  }
  t.paintedBuffers.clear();
}

async function paintStepOverlay(t: TourInstance): Promise<void> {
  const step = currentStep(t);
  const bufferId = stepBufferId(resolveStepPath(t.manifestPath, step.file_path));
  if (!bufferId) return;

  clearTourOverlays(t);
  const range = await lineRangeBytes(bufferId, step.lines[0], step.lines[1]);
  if (!range) {
    editor.warn(
      `Tour: could not resolve lines ${step.lines[0]}-${step.lines[1]} in ${step.file_path}`,
    );
    return;
  }
  // One range-wide overlay; the host tail-fills every row it spans, so
  // each line paints a full-width band — a region marker visually
  // distinct from a text selection (which never covers the empty tail
  // of a line). The bg is a theme key so the band restyles with the
  // theme, like every other tour colour. It is the band's *own* key:
  // the occurrence highlight next door is tuned for a few cells of text
  // that must stay legible and stay apart from the selection, which is
  // the wrong trade for a wash over whole line ranges.
  editor.addOverlay(bufferId, t.namespace, range[0], range[1], {
    bg: "ui.tour_step_bg",
    extendToLineEnd: true,
  });
  t.paintedBuffers.add(bufferId);
}

View on GitHub (pinned to 67894ca546)