Skip to main content

Error Recovery

When SQL has parse errors, the formatter formats valid parts normally and preserves error spans as original text. No /* ERROR */ markers — broken parts are left untouched.

Valid SELECT with broken WHERE

The SELECT and FROM clauses are valid and get formatted. The WHERE condition has a syntax error and is preserved as-is.

SELECT a, b FROM t WHERE x >
select a, b from t where x

Multiple statements — one broken

Valid statements get formatted normally. The broken statement is partially formatted.

SELECT 1; SELECT a FROM WHERE; SELECT 2
select 1;

select a from where;

select 2

Completely broken SQL

When the entire statement is unparseable, the original text is preserved.

@#$%
@#$%

Broken statement with trailing semicolon followed by more statements

A broken statement followed by a ; terminator and then another statement. The parser emits the broken portion as an AstParseErrorBase fragment that carries the original bytes — including any terminators the user typed.

File-mode formatting passes error fragments through verbatim: one ; in the input yields exactly one ; in the output, two ;; yield two ;;. The normal inter-statement ; separator is suppressed after an error fragment so the fragment's own terminators are not doubled. Re-parsing the output produces the same fragment shape, which renders identically — the round-trip is idempotent by construction.

SELECT a, b FROM t WHERE x >;
SELECT 1
select a, b from t where x >;

select 1

Broken statement followed by another broken statement

Both statements have parse errors. The first goes through the partial-format path then its >; fragment; the second goes through the verbatim hasErrors path. File-mode formatting remains idempotent across passes.

SELECT a, b FROM t WHERE x >;
SELECT a FROM WHERE
select a, b from t where x >;

select a from where

Single broken statement at EOF

One statement, broken, running to EOF with no terminator. The valid prefix is formatted normally; the broken tail is preserved verbatim. This is the baseline shape of error recovery — one statement in, one statement out.

SELECT a, b FROM t WHERE x >
select a, b from t where x >

Broken statement at EOF with trailing semicolon

One statement, broken, terminated with ; at EOF. The trailing ; is preserved exactly — the formatter does not drop or duplicate it.

SELECT a, b FROM t WHERE x >;
select a, b from t where x >;

Double semicolon preserved exactly

The user typed ;;, so the output must contain ;; — not more, not fewer. The fragment text >;; is passed through verbatim, and the inter-statement ; separator is not auto-inserted after it. One ; in → one out; two in → two out.

SELECT a, b FROM t WHERE x >;;
SELECT 1
select a, b from t where x >;;

select 1

Garbage token between valid statements

A lexically valid but syntactically nonsense token (@#$%) sitting between two valid statements. The parser emits it as an error fragment; the formatter preserves it verbatim while still formatting the surrounding statements normally.

SELECT 1;
@#$%
SELECT 2
select 1;

@#$%

select 2

Stray keyword between statements

A bare keyword like FROM on its own line between two valid statements. The parser treats it as an unparseable fragment and the formatter preserves it while keeping the surrounding statements idempotent.

SELECT 1;
FROM
SELECT 2
select 1;

FROM

select 2