SQLite: Incomplete Input / Unrecognized Token (tested)
SQLite's parser gives three different messages for a broken query, and which one you get tells you something specific about what's wrong. We fed it four kinds of broken SQL and recorded exactly which error each one produces.
1. "incomplete input" — the statement just stops
con.execute("SELECT * FROM")
sqlite3.OperationalError: incomplete input
con.execute("SELECT * FROM t WHERE")
sqlite3.OperationalError: incomplete input
con.execute("CREATE TABLE")
sqlite3.OperationalError: incomplete input
Measured: this message appears when every token so far is valid SQL grammar, but the statement ends before it's grammatically complete — a dangling keyword with nothing after it. In practice this is almost always a string-building bug: an f-string or .format() call that got truncated, a loop that appends clauses but forgot one on the last iteration, or a copy-paste that dropped the rest of the query.
2. "near X: syntax error" — a real token in the wrong place
con.execute("SELECT * FORM t")
sqlite3.OperationalError: near "FORM": syntax error
con.execute("SELEKT 1")
sqlite3.OperationalError: near "SELEKT": syntax error
con.execute("SELECT 1 FROM t WHERE id @1")
sqlite3.OperationalError: near "@1": syntax error
Measured: this fires when SQLite's tokenizer recognizes every character as a valid token, but the sequence doesn't parse — usually a typo'd keyword (FORM instead of FROM) or a token in a position the grammar doesn't allow there. The quoted text names the exact offending token, which makes this the easiest of the three to fix on sight.
3. "unrecognized token" — a character that isn't valid SQL at all
con.execute("SELECT # FROM t")
sqlite3.OperationalError: unrecognized token: "#"
con.execute("SELECT 1 FROM t WHERE id = $")
sqlite3.OperationalError: unrecognized token: "$"
con.execute("SELECT 'unterminated")
sqlite3.OperationalError: unrecognized token: "'unterminated"
Measured: this is a step below "near X" — the tokenizer itself can't classify the character, because it isn't part of SQLite's grammar in any context (a bare # or $ outside a named parameter) or because a string literal's closing quote is missing, which swallows the rest of the statement into one unterminated token. An unterminated string is the most common real-world trigger: a value containing an apostrophe concatenated directly into SQL instead of passed as a bound parameter.
4. A different error: running two statements through execute()
con.execute("SELECT 1; SELECT 2")
sqlite3.ProgrammingError: You can only execute one statement at a time.
Measured: this one isn't a parser complaint at all — it's Python's sqlite3 module deliberately rejecting multiple ;-separated statements in a single execute() call, as a safety measure against SQL injection via statement stacking. Use executescript() if you genuinely need to run several statements at once.
5. How to tell them apart fast
"Incomplete input" means something is missing — check for a truncated query string. "Near X: syntax error" names the exact wrong token — check spelling and clause order right there. "Unrecognized token" means a character the tokenizer has never heard of, or an unterminated string — check for unescaped quotes in concatenated values, which is also a strong signal you should switch to parameterized queries (? placeholders) instead of building SQL strings by hand.
Frequently asked questions
What's the difference between "incomplete input" and "near X: syntax error"?
We confirmed incomplete input means the statement ends too early while every token so far was valid, whereas near X: syntax error means a specific token exists but is in a position the grammar rejects — the message names that exact token.
Why does SQLite say "unrecognized token" instead of a syntax error for a stray #?
Because we measured it one level below a syntax error: the tokenizer itself can't classify the character as any valid SQL token type, which also happens for an unterminated string literal — the rest of the statement gets swallowed into one bad token.
Why do I get "You can only execute one statement at a time" instead of a SQL error?
We confirmed this is Python's sqlite3 module rejecting multiple semicolon-separated statements in a single execute() call as a deliberate anti-injection safeguard, not something SQLite's parser itself complains about; use executescript() if you need multiple statements.
What's the most common real cause of "incomplete input" in production code?
A truncated query string — we reproduced it from a dangling SELECT * FROM with nothing after, which matches what typically happens when string formatting or concatenation drops the rest of a query, for example on the last iteration of a loop that builds clauses.
Does an unterminated string literal always produce "unrecognized token"?
Yes — we confirmed SELECT 'unterminated with no closing quote produces unrecognized token naming the whole swallowed fragment, which is the classic signature of a value containing an apostrophe that was concatenated into SQL instead of passed as a bound parameter.
Written with AI assistance. Measured on 2026-10-03 with Python 3.13.5's built-in sqlite3 module, running each malformed SQL string directly through con.execute() and printing the exact exception text. Every message below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Python's sqlite3 is built in.