microsoft/TypeScript · error · Error

start < 0

Error message

start < 0

What it means

Thrown by `ts.createTextSpan(start, length)` when `start` is negative. `TextSpan` models a half-open range into source text; a negative start is always a bug in the caller (offset computation underflow). `createTextSpanFromBounds` delegates here via `createTextSpan(start, end - start)`, so out-of-order bounds also surface as this error.

Source

Thrown at src/compiler/utilitiesPublic.ts:448

    while (i < spans.length) {
        let span = spans[i];
        let j = i + 1;
        while (j < spans.length && textSpanIntersectsWithTextSpan(span, spans[j])) {
            const start = Math.min(span.start, spans[j].start);
            const end = Math.max(textSpanEnd(span), textSpanEnd(spans[j]));
            span = createTextSpanFromBounds(start, end);
            j++;
        }
        i = j;
        result.push(span);
    }

    return result;
}

export function createTextSpan(start: number, length: number): TextSpan {
    if (start < 0) {
        throw new Error("start < 0");
    }
    if (length < 0) {
        throw new Error("length < 0");
    }

    return { start, length };
}

export function createTextSpanFromBounds(start: number, end: number): TextSpan {
    return createTextSpan(start, end - start);
}

export function textChangeRangeNewSpan(range: TextChangeRange): TextSpan {
    return createTextSpan(range.span.start, range.newLength);
}

export function textChangeRangeIsUnchanged(range: TextChangeRange): boolean {
    return textSpanIsEmpty(range.span) && range.newLength === 0;

View on GitHub (pinned to b465fdbfe1)

Solutions

  1. Clamp `start` to `Math.max(0, computed)` before calling.
  2. Audit the upstream position math (it should be producing a non-negative absolute offset).
  3. Use `ts.createTextSpanFromBounds` with verified `start <= end` ordering.
  4. Add an assertion/log of `start`/`length` at the call site during development.

Example fix

// before
const span = ts.createTextSpan(node.end - node.getStart(), len); // can be < 0
// after
const start = Math.max(0, node.end - node.getStart());
const span = ts.createTextSpan(start, Math.max(0, len));
Defensive patterns

Strategy: validation

Validate before calling

function safeSpan(start: number, length: number): ts.TextSpan {
  if (start < 0 || length < 0) return ts.createTextSpan(0, 0);
  return ts.createTextSpan(start, length);
}

Type guard

function isValidSpanStart(start: number): boolean { return Number.isInteger(start) && start >= 0; }

Prevention

When it happens

Trigger: Calling `createTextSpan` with `start < 0`, or `createTextSpanFromBounds(start, end)` where `start` is negative — typically from subtracting offsets, parsing an empty/malformed node, or off-by-one position math in a transform/language-service plugin.

Common situations: Custom transforms that compute spans from node positions; language-service plugins mishandling end-of-file offsets; converting external 1-based line/column to 0-based absolute positions incorrectly.

Related errors


AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12). Data as JSON: /api/errors/dbd9abd04efe1f09. Report an issue: GitHub.