plandex-ai/plandex · error

start line is greater than end line: %d > %d

Error message

start line is greater than end line: %d > %d

What it means

After successfully parsing both line numbers, GetLinesWithPrefix validates the range and rejects it when the start line exceeds the end line, since that is an empty/invalid selection. This catches swapped or mis-parsed line markers in the streamed change section.

Source

Thrown at app/shared/streamed_change.go:66

		if streamedChangeSection.EndLine > 0 {
			endLine = streamedChangeSection.EndLine
		} else {
			endLine = startLine
		}
	} else {
		endLine, err = ExtractLineNumberWithPrefix(streamedChangeSection.EndLineString, prefix)

		if err != nil {
			log.Printf("Error extracting end line number: %v\n", err)
			return 0, 0, fmt.Errorf("error extracting end line number: %v", err)
		}
	}

	log.Printf("StartLine: %d, EndLine: %d\n", startLine, endLine)

	if startLine > endLine {
		log.Printf("Start line is greater than end line: %d > %d\n", startLine, endLine)
		return 0, 0, fmt.Errorf("start line is greater than end line: %d > %d", startLine, endLine)
	}

	if startLine < 1 {
		log.Printf("Start line is less than 1: %d\n", startLine)
		return 0, 0, fmt.Errorf("start line is less than 1: %d", startLine)
	}

	return startLine, endLine, nil
}

func ExtractLineNumber(line string) (int, error) {
	return ExtractLineNumberWithPrefix(line, "pdx-")
}

func ExtractLineNumberWithPrefix(line, prefix string) (int, error) {
	// Split the line at the first space to isolate the line number
	parts := strings.SplitN(line, " ", 2)

View on GitHub (pinned to e2d772072e)

Solutions

  1. Re-generate the streamed change section with correct ordering
  2. If the intent was a whole-file or open-ended range, leave EndLineString empty instead of using a smaller end line
  3. Validate parsed numbers before calling GetLines (see validationCode)
  4. Check whether custom section parsing reversed StartLineString/EndLineString assignment

Example fix

// before
section.StartLineString, section.EndLineString = endStr, startStr
// after
section.StartLineString, section.EndLineString = startStr, endStr
Defensive patterns

Strategy: validation

Validate before calling

func orderedRange(section shared.StreamedChangeSection, prefix string) error {
    s, errS := shared.ExtractLineNumberWithPrefix(section.StartLineString, prefix)
    e, errE := shared.ExtractLineNumberWithPrefix(section.EndLineString, prefix)
    if errS != nil || errE != nil { return fmt.Errorf("parse: %v %v", errS, errE) }
    if s > e { return fmt.Errorf("start %d > end %d", s, e) }
    return nil
}

Try / catch

start, end, err := GetLinesWithPrefix(section, prefix)
if err != nil {
    if strings.Contains(err.Error(), "greater than end line") {
        section.StartLineString, section.EndLineString = section.EndLineString, section.StartLineString // attempt swap
        start, end, err = GetLinesWithPrefix(section, prefix)
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: GetLines with a section whose parsed StartLine > EndLine — e.g. the LLM emitted the markers in reverse order, or prefix parsing picked the wrong numbers from adjacent lines.

Common situations: Model output confusion in long diffs; sections generated from files reordered after context capture; copy/paste of markers into the wrong order.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/472e6be17065a7a1. Report an issue: GitHub.