PythonMastery
reference 3 min read · lesson 53 of 60 in Errors

SyntaxError: '(' was never closed

1 · The lesson

read

What this error means

You opened a bracket — (, [ or { — and Python never found the one that closes it. The message names the bracket type, so you will also see '[' was never closed and '{' was never closed. The arrow points at the opening bracket that has no partner, which makes this one of the friendlier syntax errors: the line it names is usually the line to fix.

In Python 3.9 and earlier the same mistake produced a much less helpful message, SyntaxError: unexpected EOF while parsing ("EOF" is end of file), or a bare invalid syntax on the line after the real problem. If an older tutorial shows either of those for a missing bracket, this is the modern version of it.

When you see it

python
  File "main.py", line 2
    total = sum(orders
               ^
SyntaxError: '(' was never closed
python
  File "main.py", line 1
    user = {"name": "Linus", "plan": "pro"
           ^
SyntaxError: '{' was never closed

A close cousin appears when a bracket is closed, but by the wrong kind:

python
  File "main.py", line 2
    cheapest = min(prices]
                         ^
SyntaxError: closing parenthesis ']' does not match opening parenthesis '('

Python calls all three bracket types "parenthesis" in these messages. Read it as "you closed a ( with a ]".

Why it happens

Inside brackets, Python lets an expression run over as many lines as it likes. That is a feature — it is how long function calls and dictionaries are written — but it means a missing ) doesn't fail on its own line. Python carries on reading, treats the next lines as part of the same expression, and only complains when that becomes impossible.

The common causes:

  • Nested calls where one closer went missing. print(f"Total: {sum(prices)}" has three openers in a row and it's easy to count two.
  • A long dictionary or list built over several lines, with the last } or ] deleted while editing.
  • Mixed-up closers in nested structures: ["tea", "cake"} or min(prices].
  • Copying part of a multi-line call from somewhere else and leaving its tail behind.

When the error line is the wrong line

Python 3.13 is good at pointing to the opener, but in nested structures the reported line can be several lines below the mistake. Here the missing ] belongs on line 3:

python
customer = {
    "name": "Grace",
    "orders": [101, 102,
}
python
  File "main.py", line 4
    }
    ^
SyntaxError: closing parenthesis '}' does not match opening parenthesis '[' on line 3

The File line says 4, because that is where Python noticed. The message itself says "on line 3", because that is where the unclosed [ lives. Trust the second number.

How to fix it

Go to the bracket the arrow points at and find where its expression should end. Then close it there — not at the end of the line by reflex, because the right place may be in the middle:

python
orders = [120, 85, 40]
total = sum(orders)
print(f"Total: {total}")

For nested calls, count from the inside out. Each function call needs its own ):

python
prices = [3.50, 4.25, 2.00]
print("Cheapest:", min(prices))
print(f"Total: {sum(prices):.2f}")

For multi-line structures, put each closer on its own line, lined up with the line that opened it. A missing one then stands out at a glance:

python
customer = {
    "name": "Grace",
    "orders": [101, 102],
    "address": {
        "city": "Leeds",
        "postcode": "LS1 4AP",
    },
}
print(customer["address"]["city"], len(customer["orders"]))

The trailing commas are deliberate. They let you add or reorder lines without touching the line above, which is where a lot of bracket slips start.

Let the editor help. Every mainstream editor highlights the matching bracket when the cursor sits next to one — click on the opener from the error and see where its partner is, or whether it has one. VS Code also colours bracket pairs by depth, so a closer in the wrong colour is a closer in the wrong place.

If you are on Python 3.9 or older and see unexpected EOF while parsing, look for the last bracket you opened in the file. Upgrading gets you the clearer message on this page.

When you'd actually see this in real code

  • Wrapping an existing expression in round(...) or int(...) and adding the opener without the closer.
  • Building a JSON payload for an API call as a nested dict, and losing one } in a twenty-line literal.
  • Writing a long print(f"...") with function calls inside the braces.
  • Merging two branches where each side edited a different line of the same multi-line function call.

See Also

Found this useful? Share it with a friend who’s learning Python.