Python is forgiving in many ways, but its parser is not. A SyntaxError stops your program before a single line runs, which is frustrating when the fix is usually one missing character. The good news is that the same handful of mistakes account for almost every syntax error you will ever hit, and once you can recognize them on sight you fix them in seconds.
This guide walks through the most common Python syntax errors and the closely related IndentationError, TabError, and NameError cases that trip people up for the same reasons. Each section shows a broken snippet, the error Python prints, and the corrected version. Every snippet is real and copy-pasteable, so you can reproduce the error and confirm the fix in your own interpreter.
What is a syntax error in Python?
A syntax error means your code breaks the grammar of the language, so the interpreter cannot parse it into something runnable. Because parsing happens before execution, the program never starts: nothing prints, no side effects occur, you just get a traceback that ends in SyntaxError with a caret pointing at, or just after, the offending token.
Here is the canonical example, a call with no closing parenthesis.
print("Hello, Python!"
Python reaches the end of the file still waiting for the ) that closes the call, so it reports the problem at the end of input.
SyntaxError: '(' was never closed
One thing worth fixing in your mental model early: a syntax error is not the same as a runtime error. Syntax errors are caught at parse time and stop the program from starting at all. Runtime errors, like dividing by zero or opening a file that does not exist, happen while a syntactically valid program is running. This guide is about the first kind, the ones that never let your code run in the first place.
Common Python syntax errors and how to fix them
The sections below follow roughly the order you are likely to meet these mistakes. Each one is small and self-contained, so feel free to jump to whichever error message you are staring at right now.
1. Missing or mismatched parentheses
Parentheses group expressions and call functions, and they have to balance. An unclosed opening parenthesis is one of the most common syntax errors, especially in longer conditionals where the closer is easy to drop.
if (x > 10: print("x is greater than 10")
Python expects a closing parenthesis before the colon and tells you so.
SyntaxError: closing parenthesis ':' does not match opening parenthesis '('
The fix is to make sure every opening bracket has a matching closer of the same kind. Close the parenthesis before the colon and the conditional parses cleanly. The same rule applies to square brackets [] and curly braces {}; editors that highlight matching brackets catch most of these for you.
if (x > 10): print("x is greater than 10")
2. Missing colon in a control statement
Every compound statement header in Python ends with a colon: if, elif, else, for, while, def, class, try, and the rest. Leaving off the colon is a classic mistake when you come from a language that uses braces instead.
if x > 5 print("x is greater than 5")
Modern Python points right at the missing token.
SyntaxError: expected ':'
Add the colon at the end of the header line. Whenever you write a statement that starts a new indented block, your eye should automatically check for the trailing colon.
if x > 5: print("x is greater than 5")
3. Expected an indented block (IndentationError)
Python uses indentation instead of braces to mark code blocks, so the body of every if, loop, or function must be indented. Write a header with a colon and then forget to indent the next line, and the parser has no block to attach.
for i in range(5): print(i)
The interpreter reports that it wanted an indented block after the loop header.
IndentationError: expected an indented block after 'for' statement on line 1
Indent the body by four spaces, the standard Python convention. The indentation is the syntax here, not a style preference: it is how Python knows which lines belong to the loop.
for i in range(5): print(i)
4. Unexpected indent (IndentationError)
The opposite mistake is indenting a line that should sit at the same level as its neighbors. Indentation has to be consistent within a block, so a stray extra space or two on one line breaks the parse.
def example(): print("First line") print("Second line")
The second print is indented more than the first for no reason, and Python rejects it.
IndentationError: unexpected indent
Line up every statement in the same block at the same column. Pick four spaces per level and keep it uniform, and your editor's auto-indent will usually keep you honest.
def example(): print("First line") print("Second line")
5. Mixing tabs and spaces (TabError)
A particularly sneaky indentation bug is mixing tabs and spaces in the same block. The two can look identical on screen, but Python treats them as different and raises a dedicated TabError. In the snippet below the first body line uses spaces and the second uses a tab.
def greet(name): message = "Hi " + name return message
Even though both lines line up visually, Python cannot tell whether they are at the same level.
TabError: inconsistent use of tabs and spaces in indentation
Settle on spaces, which PEP 8 recommends, and never mix. Configure your editor to insert spaces when you press Tab, and run a search-and-replace on any file that already has a mix. Re-indenting both body lines with four spaces clears the error.
Tab-versus-space bugs are invisible until you turn on whitespace rendering. Most editors have a "show whitespace" or "render control characters" toggle that draws tabs and spaces as distinct marks. Turn it on once and these errors stop being mysterious.
6. EOL while scanning a string literal
A string has to open and close on the same line with matching quotes. Forget the closing quote, or close it with the wrong kind, and Python hits the end of the line still inside the string.
name = 'John"
The string opens with a single quote but closes with a double quote, so it is never terminated.
SyntaxError: unterminated string literal (detected at line 1)
Use the same quote character on both ends. If your text contains a quote, wrap the string in the other kind, for example "O'Brien", or use a triple-quoted string for text that spans multiple lines. Older Python versions phrase this same error as EOL while scanning string literal, but the cause is identical.
name = 'John'
7. EOF while scanning (unexpected end of file)
Closely related is the end-of-file version: an opening bracket or quote that never closes before the file runs out. This is the unclosed-call case from earlier, and it is worth its own section because the error message names a different cause. A multi-line structure with a missing closer is the usual culprit.
numbers = [1, 2, 3 print(sum(numbers))
Because the list is never closed, Python keeps reading, treats the next line as part of the list, and runs off the end of the file.
SyntaxError: '[' was never closed
Close the bracket where the structure ends. When an error points at the very end of a file, the real problem is almost always an opener several lines above that was never matched, so scan upward from the caret.
numbers = [1, 2, 3] print(sum(numbers))
8. Invalid assignment: = versus ==
A single = assigns a value; a double == compares two values. Use assignment where a comparison belongs, such as in an if condition, and Python rejects it because you cannot assign inside a plain conditional test.
if x = 10: print("x is 10")
Recent Python versions are explicit about what you probably meant.
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?
Use == to compare and reserve = for assignment. If you genuinely want to assign as part of an expression, that is what the walrus operator := is for, but for an ordinary condition you almost always mean ==.
if x == 10: print("x is 10")
Once your parser runs clean, the hard part of a scraper is the fetch: rendering JavaScript pages and rotating IPs so you do not get blocked. The Crawling API handles both behind a single request and returns finished HTML, so your error-free Python keeps parsing data instead of fighting a headless browser fleet and a proxy pool.
9. Using a reserved keyword as a name
Python reserves words like for, if, class, return, and import for the language itself. Try to use one as a variable name and the parser sees a keyword where it expects an identifier.
for = 10
Assigning to for is invalid because for can only start a loop.
SyntaxError: invalid syntax
Pick a name that is not reserved, ideally one that describes the value. If you are unsure whether a name is taken, Python's own keyword module lists every reserved word; checking a name against keyword.kwlist settles it instantly.
import keyword num_for = 10 print("for" in keyword.kwlist) # True, so it is off limits
10. Misplaced or missing commas
Commas separate items in lists, tuples, dictionaries, and argument lists. Drop one between two string literals and Python tries to read them as a single expression, which is invalid.
items = ["apple" "banana", "cherry"]
Python points at the second string, where a comma was expected.
SyntaxError: invalid syntax. Perhaps you forgot a comma?
Put a comma between each item. This one bites often because Python silently concatenates two adjacent string literals, so "apple" "banana" sometimes parses without error and produces "applebanana", a confusing bug rather than a clean failure. Always comma-separate your items explicitly.
items = ["apple", "banana", "cherry"]
11. Improper import statements
Imports have their own grammar. Forget to name what you are importing, and the from ... import form is left incomplete.
from math import
The parser reaches the end of the line still expecting a name to import.
SyntaxError: invalid syntax
Name what you are importing, or import the whole module. Both forms below are valid: import the module and reach into it with dot notation, or pull specific names out of it.
import os import sys from math import sqrt
12. print as a statement instead of a function
In Python 2, print was a statement and you wrote it without parentheses. In Python 3 it is a regular function, so the old form is a syntax error. This still trips up anyone copying examples from old tutorials.
print "Hello, Python!"
Python 3 even suggests the correction in the message.
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
Wrap the arguments in parentheses, the same way you call any other function. The same applies to exec, which also became a function in Python 3.
print("Hello, Python!")
13. NameError from a typo
This last one is not strictly a syntax error: the code parses fine, so it fails at runtime rather than at parse time. It belongs here because the cause is the same family of small slips, and because the fix is just as quick. Misspell a variable name and Python cannot find it.
message = "hello" print(mesage)
The name mesage was never defined, so Python raises a NameError and helpfully guesses what you meant.
NameError: name 'mesage' is not defined. Did you mean: 'message'?
Fix the spelling so the name matches its definition. Because this error only appears when the line actually runs, it can hide in a branch you rarely hit, which is one more reason to test your code in small pieces rather than all at once.
message = "hello" print(message)
How to avoid Python syntax errors
You will never stop making these mistakes entirely, but you can catch nearly all of them before you run anything. A few habits do most of the work.
- Use an editor with syntax highlighting. VS Code, PyCharm, and even lightweight editors like Thonny flag unmatched brackets, bad indentation, and broken strings as you type, so most errors never reach the interpreter.
-
Pick four spaces and never mix tabs. Configure your editor to insert spaces when you press Tab. Consistent indentation alone removes the entire
IndentationErrorandTabErrorfamily. - Run a linter. Tools like Pylint, Flake8, and Ruff scan your code for syntax problems, missing commas, and undefined names before you run it, and most plug straight into your editor.
- Read the error message and the caret. Modern Python points at the exact token and often suggests the fix. The line number is where Python noticed the problem, which for unclosed brackets is usually a line or two below the real cause.
- Test in small pieces. Run a few lines at a time rather than a whole script at once. Errors are far easier to locate when only a handful of new lines could be responsible.
These same habits keep your code clean once you move past toy snippets into real projects, including scrapers. If you want a full walkthrough that puts working Python to use, see how to scrape a website with Python, and for a tour of the tools you will reach for, the best Python web scraping libraries.
Key takeaways
- Syntax errors stop the program before it runs. Unlike runtime errors, they are caught at parse time, so nothing executes until you fix them.
- Most syntax errors are punctuation. A missing colon, an unclosed bracket, a mismatched quote, or a dropped comma accounts for the large majority of cases.
- Indentation is syntax, not style. Indent block bodies consistently, use four spaces, and never mix tabs and spaces, which avoids the entire IndentationError and TabError family.
- = assigns and == compares. Using one where the other belongs is a frequent slip that modern Python now points out directly.
- Read the message and the caret. Recent Python versions name the exact token and often suggest the fix, and for end-of-file errors the real cause is usually an unclosed opener above.
Frequently Asked Questions (FAQs)
What is the difference between a syntax error and a runtime error in Python?
A syntax error breaks the grammar of the language, so the interpreter cannot parse your code and the program never starts. A runtime error happens while a valid program is running, when an operation fails, such as dividing by zero or opening a file that does not exist. Syntax errors are caught before execution; runtime errors are caught during it.
Why does Python care so much about indentation?
Python uses indentation instead of braces to define code blocks, which keeps code readable and uniform. Because the whitespace is the syntax, inconsistent indentation is a genuine error rather than a style nitpick. Settle on four spaces per level and let your editor enforce it, and indentation stops being a source of bugs.
How do I fix "SyntaxError: unexpected EOF while parsing"?
That message means an opening bracket, parenthesis, or quote was never closed, so Python ran off the end of the file still waiting for the closer. Start at the line the error points to and scan upward for an unmatched opener. Newer Python versions phrase the same problem more specifically, for example '(' was never closed, which tells you exactly which character to chase.
Why do I get a TabError when my code looks correctly indented?
Because tabs and spaces can look identical on screen while Python treats them as different characters. If one line in a block uses a tab and another uses spaces, the indentation is inconsistent even though it lines up visually. Turn on whitespace rendering in your editor, convert everything to spaces, and the error disappears.
How can I catch syntax errors before running my code?
Use an editor with syntax highlighting and a linter such as Pylint, Flake8, or Ruff. These flag unmatched brackets, missing commas, bad indentation, and undefined names as you type, so most mistakes never reach the interpreter. Testing small pieces of code at a time also isolates any error that does slip through.
Is print a function or a statement in Python?
In Python 3 it is a function, so you must call it with parentheses: print("text"). The bare print "text" form was valid only in Python 2 and is now a syntax error. If you see "Missing parentheses in call to print," you are reading Python 2 style code in a Python 3 interpreter.
Crawl any site at scale, without fighting infrastructure.
Crawlbase handles proxies, fingerprints, and CAPTCHAs so your team ships data pipelines instead of maintaining crawl plumbing. 1,000 requests free, no card required.
