8. Errors and Exceptions¶
Until now error messages haven’t been more than mentioned, but if you have tried out the examples you have probably seen some. There are (at least) two distinguishable kinds of errors: syntax errors and exceptions.
8.1. Syntax Errors¶
Syntax errors, also known as parsing errors, are perhaps the most common kind of complaint you get while you are still learning Python:
The parser repeats the offending line and displays a little ‘arrow’ pointing at the earliest point in the line where the error was detected. The error is caused by (or at least detected at) the token preceding the arrow: in the example, the error is detected at the function print() , since a colon ( ‘:’ ) is missing before it. File name and line number are printed so you know where to look in case the input came from a script.
8.2. Exceptions¶
Even if a statement or expression is syntactically correct, it may cause an error when an attempt is made to execute it. Errors detected during execution are called exceptions and are not unconditionally fatal: you will soon learn how to handle them in Python programs. Most exceptions are not handled by programs, however, and result in error messages as shown here:
The last line of the error message indicates what happened. Exceptions come in different types, and the type is printed as part of the message: the types in the example are ZeroDivisionError , NameError and TypeError . The string printed as the exception type is the name of the built-in exception that occurred. This is true for all built-in exceptions, but need not be true for user-defined exceptions (although it is a useful convention). Standard exception names are built-in identifiers (not reserved keywords).
The rest of the line provides detail based on the type of exception and what caused it.
The preceding part of the error message shows the context where the exception occurred, in the form of a stack traceback. In general it contains a stack traceback listing source lines; however, it will not display lines read from standard input.
Built-in Exceptions lists the built-in exceptions and their meanings.
8.3. Handling Exceptions¶
It is possible to write programs that handle selected exceptions. Look at the following example, which asks the user for input until a valid integer has been entered, but allows the user to interrupt the program (using Control — C or whatever the operating system supports); note that a user-generated interruption is signalled by raising the KeyboardInterrupt exception.
The try statement works as follows.
First, the try clause (the statement(s) between the try and except keywords) is executed.
If no exception occurs, the except clause is skipped and execution of the try statement is finished.
If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then, if its type matches the exception named after the except keyword, the except clause is executed, and then execution continues after the try/except block.
If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is found, it is an unhandled exception and execution stops with a message as shown above.
A try statement may have more than one except clause, to specify handlers for different exceptions. At most one handler will be executed. Handlers only handle exceptions that occur in the corresponding try clause, not in other handlers of the same try statement. An except clause may name multiple exceptions as a parenthesized tuple, for example:
A class in an except clause is compatible with an exception if it is the same class or a base class thereof (but not the other way around — an except clause listing a derived class is not compatible with a base class). For example, the following code will print B, C, D in that order:
Note that if the except clauses were reversed (with except B first), it would have printed B, B, B — the first matching except clause is triggered.
When an exception occurs, it may have associated values, also known as the exception’s arguments. The presence and types of the arguments depend on the exception type.
The except clause may specify a variable after the exception name. The variable is bound to the exception instance which typically has an args attribute that stores the arguments. For convenience, builtin exception types define __str__() to print all the arguments without explicitly accessing .args .
The exception’s __str__() output is printed as the last part (‘detail’) of the message for unhandled exceptions.
BaseException is the common base class of all exceptions. One of its subclasses, Exception , is the base class of all the non-fatal exceptions. Exceptions which are not subclasses of Exception are not typically handled, because they are used to indicate that the program should terminate. They include SystemExit which is raised by sys.exit() and KeyboardInterrupt which is raised when a user wishes to interrupt the program.
Exception can be used as a wildcard that catches (almost) everything. However, it is good practice to be as specific as possible with the types of exceptions that we intend to handle, and to allow any unexpected exceptions to propagate on.
The most common pattern for handling Exception is to print or log the exception and then re-raise it (allowing a caller to handle the exception as well):
The try … except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example:
The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try … except statement.
Exception handlers do not handle only exceptions that occur immediately in the try clause, but also those that occur inside functions that are called (even indirectly) in the try clause. For example:
8.4. Raising Exceptions¶
The raise statement allows the programmer to force a specified exception to occur. For example:
The sole argument to raise indicates the exception to be raised. This must be either an exception instance or an exception class (a class that derives from BaseException , such as Exception or one of its subclasses). If an exception class is passed, it will be implicitly instantiated by calling its constructor with no arguments:
If you need to determine whether an exception was raised but don’t intend to handle it, a simpler form of the raise statement allows you to re-raise the exception:
8.5. Exception Chaining¶
If an unhandled exception occurs inside an except section, it will have the exception being handled attached to it and included in the error message:
To indicate that an exception is a direct consequence of another, the raise statement allows an optional from clause:
This can be useful when you are transforming exceptions. For example:
It also allows disabling automatic exception chaining using the from None idiom:
For more information about chaining mechanics, see Built-in Exceptions .
8.6. User-defined Exceptions¶
Programs may name their own exceptions by creating a new exception class (see Classes for more about Python classes). Exceptions should typically be derived from the Exception class, either directly or indirectly.
Exception classes can be defined which do anything any other class can do, but are usually kept simple, often only offering a number of attributes that allow information about the error to be extracted by handlers for the exception.
Most exceptions are defined with names that end in “Error”, similar to the naming of the standard exceptions.
Many standard modules define their own exceptions to report errors that may occur in functions they define.
8.7. Defining Clean-up Actions¶
The try statement has another optional clause which is intended to define clean-up actions that must be executed under all circumstances. For example:
If a finally clause is present, the finally clause will execute as the last task before the try statement completes. The finally clause runs whether or not the try statement produces an exception. The following points discuss more complex cases when an exception occurs:
If an exception occurs during execution of the try clause, the exception may be handled by an except clause. If the exception is not handled by an except clause, the exception is re-raised after the finally clause has been executed.
An exception could occur during execution of an except or else clause. Again, the exception is re-raised after the finally clause has been executed.
If the finally clause executes a break , continue or return statement, exceptions are not re-raised.
If the try statement reaches a break , continue or return statement, the finally clause will execute just prior to the break , continue or return statement’s execution.
If a finally clause includes a return statement, the returned value will be the one from the finally clause’s return statement, not the value from the try clause’s return statement.
A more complicated example:
As you can see, the finally clause is executed in any event. The TypeError raised by dividing two strings is not handled by the except clause and therefore re-raised after the finally clause has been executed.
In real world applications, the finally clause is useful for releasing external resources (such as files or network connections), regardless of whether the use of the resource was successful.
8.8. Predefined Clean-up Actions¶
Some objects define standard clean-up actions to be undertaken when the object is no longer needed, regardless of whether or not the operation using the object succeeded or failed. Look at the following example, which tries to open a file and print its contents to the screen.
The problem with this code is that it leaves the file open for an indeterminate amount of time after this part of the code has finished executing. This is not an issue in simple scripts, but can be a problem for larger applications. The with statement allows objects like files to be used in a way that ensures they are always cleaned up promptly and correctly.
After the statement is executed, the file f is always closed, even if a problem was encountered while processing the lines. Objects which, like files, provide predefined clean-up actions will indicate this in their documentation.
8.9. Raising and Handling Multiple Unrelated Exceptions¶
There are situations where it is necessary to report several exceptions that have occurred. This is often the case in concurrency frameworks, when several tasks may have failed in parallel, but there are also other use cases where it is desirable to continue execution and collect multiple errors rather than raise the first exception.
The builtin ExceptionGroup wraps a list of exception instances so that they can be raised together. It is an exception itself, so it can be caught like any other exception.
By using except* instead of except , we can selectively handle only the exceptions in the group that match a certain type. In the following example, which shows a nested exception group, each except* clause extracts from the group exceptions of a certain type while letting all other exceptions propagate to other clauses and eventually to be reraised.
Note that the exceptions nested in an exception group must be instances, not types. This is because in practice the exceptions would typically be ones that have already been raised and caught by the program, along the following pattern:
8.10. Enriching Exceptions with Notes¶
When an exception is created in order to be raised, it is usually initialized with information that describes the error that has occurred. There are cases where it is useful to add information after the exception was caught. For this purpose, exceptions have a method add_note(note) that accepts a string and adds it to the exception’s notes list. The standard traceback rendering includes all notes, in the order they were added, after the exception.
For example, when collecting exceptions into an exception group, we may want to add context information for the individual errors. In the following each exception in the group has a note indicating when this error has occurred.
How to Fix Invalid SyntaxError in Python
The Python SyntaxError occurs when the interpreter encounters invalid syntax in code. When Python code is executed, the interpreter parses it to convert it into bytecode. If the interpreter finds any invalid syntax during the parsing stage, a SyntaxError is thrown.
What Causes Invalid SyntaxError
Some of the most common causes of syntax errors in Python are:
- Misspelled reserved keywords
- Missing quotes
- Missing required spaces
- Missing operators
- Invalid usage of blocks (e.g. if-else, loops)
- Invalid variable declarations
- Invalid function definitions or calls
Python Invalid SyntaxError Example
Here’s an example of a Python SyntaxError thrown due to missing quotes:
In the above example, since the string “Hello World” is attempted to be printed without using quotes, a SyntaxError is thrown:
How to Fix Invalid SyntaxError in Python
To avoid syntax errors, IDEs that understand Python syntax can be used as they highlight the lines containing the problem. These issues can then be fixed before code is executed.
If a SyntaxError occurs after execution, the traceback can be inspected to detect where the issue exists in code
The traceback from the earlier example can be inspected to fix the issue:
Here, it can be seen that the issue exists in line 1. When this line is inspected, it should be clear that the error occurred because of missing quotes in the string. When these missing quotes are added, the syntax issue is fixed:
The above code runs successfully and produces the correct output as expected:
Track, Analyze and Manage Errors With Rollbar
Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Python errors easier than ever. Try it today!
Invalid Syntax in Python: Common Reasons for SyntaxError
Python is known for its simple syntax. However, when you’re learning Python for the first time or when you’ve come to Python with a solid background in another programming language, you may run into some things that Python doesn’t allow. If you’ve ever received a SyntaxError when trying to run your Python code, then this guide can help you. Throughout this tutorial, you’ll see common examples of invalid syntax in Python and learn how to resolve the issue.
By the end of this tutorial, you’ll be able to:
- Identify invalid syntax in Python
- Make sense of SyntaxError tracebacks
- Resolve invalid syntax or prevent it altogether
Free Bonus: 5 Thoughts On Python Mastery, a free course for Python developers that shows you the roadmap and the mindset you’ll need to take your Python skills to the next level.
Invalid Syntax in Python
When you run your Python code, the interpreter will first parse it to convert it into Python byte code, which it will then execute. The interpreter will find any invalid syntax in Python during this first stage of program execution, also known as the parsing stage. If the interpreter can’t parse your Python code successfully, then this means that you used invalid syntax somewhere in your code. The interpreter will attempt to show you where that error occurred.
When you’re learning Python for the first time, it can be frustrating to get a SyntaxError . Python will attempt to help you determine where the invalid syntax is in your code, but the traceback it provides can be a little confusing. Sometimes, the code it points to is perfectly fine.
Note: If your code is syntactically correct, then you may get other exceptions raised that are not a SyntaxError . To learn more about Python’s other exceptions and how to handle them, check out Python Exceptions: An Introduction.
You can’t handle invalid syntax in Python like other exceptions. Even if you tried to wrap a try and except block around code with invalid syntax, you’d still see the interpreter raise a SyntaxError .
SyntaxError Exception and Traceback
When the interpreter encounters invalid syntax in Python code, it will raise a SyntaxError exception and provide a traceback with some helpful information to help you debug the error. Here’s some code that contains invalid syntax in Python:
You can see the invalid syntax in the dictionary literal on line 4. The second entry, ‘jim’ , is missing a comma. If you tried to run this code as-is, then you’d get the following traceback:
Note that the traceback message locates the error in line 5, not line 4. The Python interpreter is attempting to point out where the invalid syntax is. However, it can only really point to where it first noticed a problem. When you get a SyntaxError traceback and the code that the traceback is pointing to looks fine, then you’ll want to start moving backward through the code until you can determine what’s wrong.
In the example above, there isn’t a problem with leaving out a comma, depending on what comes after it. For example, there’s no problem with a missing comma after ‘michael’ in line 5. But once the interpreter encounters something that doesn’t make sense, it can only point you to the first thing it found that it couldn’t understand.
Note: This tutorial assumes that you know the basics of Python’s tracebacks. To learn more about the Python traceback and how to read them, check out Understanding the Python Traceback and Getting the Most out of a Python Traceback.
There are a few elements of a SyntaxError traceback that can help you determine where the invalid syntax is in your code:
- The file name where the invalid syntax was encountered
- The line number and reproduced line of code where the issue was encountered
- A caret ( ^ ) on the line below the reproduced code, which shows you the point in the code that has a problem
- The error message that comes after the exception type SyntaxError , which can provide information to help you determine the problem
In the example above, the file name given was theofficefacts.py , the line number was 5, and the caret pointed to the closing quote of the dictionary key michael . The SyntaxError traceback might not point to the real problem, but it will point to the first place where the interpreter couldn’t make sense of the syntax.
There are two other exceptions that you might see Python raise. These are equivalent to SyntaxError but have different names:
- IndentationError
- TabError
These exceptions both inherit from the SyntaxError class, but they’re special cases where indentation is concerned. An IndentationError is raised when the indentation levels of your code don’t match up. A TabError is raised when your code uses both tabs and spaces in the same file. You’ll take a closer look at these exceptions in a later section.
Common Syntax Problems
When you encounter a SyntaxError for the first time, it’s helpful to know why there was a problem and what you might do to fix the invalid syntax in your Python code. In the sections below, you’ll see some of the more common reasons that a SyntaxError might be raised and how you can fix them.
Misusing the Assignment Operator ( = )
There are several cases in Python where you’re not able to make assignments to objects. Some examples are assigning to literals and function calls. In the code block below, you can see a few examples that attempt to do this and the resulting SyntaxError tracebacks:
The first example tries to assign the value 5 to the len() call. The SyntaxError message is very helpful in this case. It tells you that you can’t assign a value to a function call.
The second and third examples try to assign a string and an integer to literals. The same rule is true for other literal values. Once again, the traceback messages indicate that the problem occurs when you attempt to assign a value to a literal.
Note: The examples above are missing the repeated code line and caret ( ^ ) pointing to the problem in the traceback. The exception and traceback you see will be different when you’re in the REPL vs trying to execute this code from a file. If this code were in a file, then you’d get the repeated code line and caret pointing to the problem, as you saw in other cases throughout this tutorial.
It’s likely that your intent isn’t to assign a value to a literal or a function call. For instance, this can occur if you accidentally leave off the extra equals sign ( = ), which would turn the assignment into a comparison. A comparison, as you can see below, would be valid:
Most of the time, when Python tells you that you’re making an assignment to something that can’t be assigned to, you first might want to check to make sure that the statement shouldn’t be a Boolean expression instead. You may also run into this issue when you’re trying to assign a value to a Python keyword, which you’ll cover in the next section.
Misspelling, Missing, or Misusing Python Keywords
Python keywords are a set of protected words that have special meaning in Python. These are words you can’t use as identifiers, variables, or function names in your code. They’re a part of the language and can only be used in the context that Python allows.
There are three common ways that you can mistakenly use keywords:
- Misspelling a keyword
- Missing a keyword
- Misusing a keyword
If you misspell a keyword in your Python code, then you’ll get a SyntaxError . For example, here’s what happens if you spell the keyword for incorrectly:
The message reads SyntaxError: invalid syntax , but that’s not very helpful. The traceback points to the first place where Python could detect that something was wrong. To fix this sort of error, make sure that all of your Python keywords are spelled correctly.
Another common issue with keywords is when you miss them altogether:
Once again, the exception message isn’t that helpful, but the traceback does attempt to point you in the right direction. If you move back from the caret, then you can see that the in keyword is missing from the for loop syntax.
You can also misuse a protected Python keyword. Remember, keywords are only allowed to be used in specific situations. If you use them incorrectly, then you’ll have invalid syntax in your Python code. A common example of this is the use of continue or break outside of a loop. This can easily happen during development when you’re implementing things and happen to move logic outside of a loop:
Here, Python does a great job of telling you exactly what’s wrong. The messages «‘break’ outside loop» and «‘continue’ not properly in loop» help you figure out exactly what to do. If this code were in a file, then Python would also have the caret pointing right to the misused keyword.
Another example is if you attempt to assign a Python keyword to a variable or use a keyword to define a function:
When you attempt to assign a value to pass , or when you attempt to define a new function called pass , you’ll get a SyntaxError and see the «invalid syntax» message again.
It might be a little harder to solve this type of invalid syntax in Python code because the code looks fine from the outside. If your code looks good, but you’re still getting a SyntaxError , then you might consider checking the variable name or function name you want to use against the keyword list for the version of Python that you’re using.
The list of protected keywords has changed with each new version of Python. For example, in Python 3.6 you could use await as a variable name or function name, but as of Python 3.7, that word has been added to the keyword list. Now, if you try to use await as a variable or function name, this will cause a SyntaxError if your code is for Python 3.7 or later.
Another example of this is print , which differs in Python 2 vs Python 3:
| Version | print Type | Takes A Value |
|---|---|---|
| Python 2 | keyword | no |
| Python 3 | built-in function | yes |
print is a keyword in Python 2, so you can’t assign a value to it. In Python 3, however, it’s a built-in function that can be assigned values.
You can run the following code to see the list of keywords in whatever version of Python you’re running:
keyword also provides the useful keyword.iskeyword() . If you just need a quick way to check the pass variable, then you can use the following one-liner:
This code will tell you quickly if the identifier that you’re trying to use is a keyword or not.
Missing Parentheses, Brackets, and Quotes
Often, the cause of invalid syntax in Python code is a missed or mismatched closing parenthesis, bracket, or quote. These can be hard to spot in very long lines of nested parentheses or longer multi-line blocks. You can spot mismatched or missing quotes with the help of Python’s tracebacks:
Here, the traceback points to the invalid code where there’s a t’ after a closing single quote. To fix this, you can make one of two changes:
- Escape the single quote with a backslash ( ‘don\’t’ )
- Surround the entire string in double-quotes instead ( «don’t» )
Another common mistake is to forget to close string. With both double-quoted and single-quoted strings, the situation and traceback are the same:
This time, the caret in the traceback points right to the problem code. The SyntaxError message, «EOL while scanning string literal» , is a little more specific and helpful in determining the problem. This means that the Python interpreter got to the end of a line (EOL) before an open string was closed. To fix this, close the string with a quote that matches the one you used to start it. In this case, that would be a double quote ( » ).
Quotes missing from statements inside an f-string can also lead to invalid syntax in Python:
Here, the reference to the ages dictionary inside the printed f-string is missing the closing double quote from the key reference. The resulting traceback is as follows:
Python identifies the problem and tells you that it exists inside the f-string. The message «unterminated string» also indicates what the problem is. The caret in this case only points to the beginning of the f-string.
This might not be as helpful as when the caret points to the problem area of the f-string, but it does narrow down where you need to look. There’s an unterminated string somewhere inside that f-string. You just have to find out where. To fix this problem, make sure that all internal f-string quotes and brackets are present.
The situation is mostly the same for missing parentheses and brackets. If you leave out the closing square bracket from a list, for example, then Python will spot that and point it out. There are a few variations of this, however. The first is to leave the closing bracket off of the list:
When you run this code, you’ll be told that there’s a problem with the call to print() :
What’s happening here is that Python thinks the list contains three elements: 1 , 2 , and 3 print(foo()) . Python uses whitespace to group things logically, and because there’s no comma or bracket separating 3 from print(foo()) , Python lumps them together as the third element of the list.
Another variation is to add a trailing comma after the last element in the list while still leaving off the closing square bracket:
Now you get a different traceback:
In the previous example, 3 and print(foo()) were lumped together as one element, but here you see a comma separating the two. Now, the call to print(foo()) gets added as the fourth element of the list, and Python reaches the end of the file without the closing bracket. The traceback tells you that Python got to the end of the file (EOF), but it was expecting something else.
In this example, Python was expecting a closing bracket ( ] ), but the repeated line and caret are not very helpful. Missing parentheses and brackets are tough for Python to identify. Sometimes the only thing you can do is start from the caret and move backward until you can identify what’s missing or wrong.
Mistaking Dictionary Syntax
You saw earlier that you could get a SyntaxError if you leave the comma off of a dictionary element. Another form of invalid syntax with Python dictionaries is the use of the equals sign ( = ) to separate keys and values, instead of the colon:
Once again, this error message is not very helpful. The repeated line and caret, however, are very helpful! They’re pointing right to the problem character.
This type of issue is common if you confuse Python syntax with that of other programming languages. You’ll also see this if you confuse the act of defining a dictionary with a dict() call. To fix this, you could replace the equals sign with a colon. You can also switch to using dict() :
You can use dict() to define the dictionary if that syntax is more helpful.
Using the Wrong Indentation
There are two sub-classes of SyntaxError that deal with indentation issues specifically:
- IndentationError
- TabError
While other programming languages use curly braces to denote blocks of code, Python uses whitespace. That means that Python expects the whitespace in your code to behave predictably. It will raise an IndentationError if there’s a line in a code block that has the wrong number of spaces:
This might be tough to see, but line 5 is only indented 2 spaces. It should be in line with the for loop statement, which is 4 spaces over. Thankfully, Python can spot this easily and will quickly tell you what the issue is.
There’s also a bit of ambiguity here, though. Is the print(‘done’) line intended to be after the for loop or inside the for loop block? When you run the above code, you’ll see the following error:
Even though the traceback looks a lot like the SyntaxError traceback, it’s actually an IndentationError . The error message is also very helpful. It tells you that the indentation level of the line doesn’t match any other indentation level. In other words, print(‘done’) is indented 2 spaces, but Python can’t find any other line of code that matches this level of indentation. You can fix this quickly by making sure the code lines up with the expected indentation level.
The other type of SyntaxError is the TabError , which you’ll see whenever there’s a line that contains either tabs or spaces for its indentation, while the rest of the file contains the other. This might go hidden until Python points it out to you!
If your tab size is the same width as the number of spaces in each indentation level, then it might look like all the lines are at the same level. However, if one line is indented using spaces and the other is indented with tabs, then Python will point this out as a problem:
Here, line 5 is indented with a tab instead of 4 spaces. This code block could look perfectly fine to you, or it could look completely wrong, depending on your system settings.
Python, however, will notice the issue immediately. But before you run the code to see what Python will tell you is wrong, it might be helpful for you to see an example of what the code looks like under different tab width settings:
Notice the difference in display between the three examples above. Most of the code uses 4 spaces for each indentation level, but line 5 uses a single tab in all three examples. The width of the tab changes, based on the tab width setting:
- If the tab width is 4, then the print statement will look like it’s outside the for loop. The console will print ‘done’ at the end of the loop.
- If the tab width is 8, which is standard for a lot of systems, then the print statement will look like it’s inside the for loop. The console will print ‘done’ after each number.
- If the tab width is 3, then the print statement looks out of place. In this case, line 5 doesn’t match up with any indentation level.
When you run the code, you’ll get the following error and traceback:
Notice the TabError instead of the usual SyntaxError . Python points out the problem line and gives you a helpful error message. It tells you clearly that there’s a mixture of tabs and spaces used for indentation in the same file.
The solution to this is to make all lines in the same Python code file use either tabs or spaces, but not both. For the code blocks above, the fix would be to remove the tab and replace it with 4 spaces, which will print ‘done’ after the for loop has finished.
Defining and Calling Functions
You might run into invalid syntax in Python when you’re defining or calling functions. For example, you’ll see a SyntaxError if you use a semicolon instead of a colon at the end of a function definition:
The traceback here is very helpful, with the caret pointing right to the problem character. You can clear up this invalid syntax in Python by switching out the semicolon for a colon.
In addition, keyword arguments in both function definitions and function calls need to be in the right order. Keyword arguments always come after positional arguments. Failure to use this ordering will lead to a SyntaxError :
Here, once again, the error message is very helpful in telling you exactly what is wrong with the line.
Changing Python Versions
Sometimes, code that works perfectly fine in one version of Python breaks in a newer version. This is due to official changes in language syntax. The most well-known example of this is the print statement, which went from a keyword in Python 2 to a built-in function in Python 3:
This is one of the examples where the error message provided with the SyntaxError shines! Not only does it tell you that you’re missing parenthesis in the print call, but it also provides the correct code to help you fix the statement.
Another problem you might encounter is when you’re reading or learning about syntax that’s valid syntax in a newer version of Python, but isn’t valid in the version you’re writing in. An example of this is the f-string syntax, which doesn’t exist in Python versions before 3.6:
In versions of Python before 3.6, the interpreter doesn’t know anything about the f-string syntax and will just provide a generic «invalid syntax» message. The problem, in this case, is that the code looks perfectly fine, but it was run with an older version of Python. When in doubt, double-check which version of Python you’re running!
Python syntax is continuing to evolve, and there are some cool new features introduced in Python 3.8:
If you want to try out some of these new features, then you need to make sure you’re working in a Python 3.8 environment. Otherwise, you’ll get a SyntaxError .
Python 3.8 also provides the new SyntaxWarning . You’ll see this warning in situations where the syntax is valid but still looks suspicious. An example of this would be if you were missing a comma between two tuples in a list. This would be valid syntax in Python versions before 3.8, but the code would raise a TypeError because a tuple is not callable:
This TypeError means that you can’t call a tuple like a function, which is what the Python interpreter thinks you’re doing.
In Python 3.8, this code still raises the TypeError , but now you’ll also see a SyntaxWarning that indicates how you can go about fixing the problem:
The helpful message accompanying the new SyntaxWarning even provides a hint ( «perhaps you missed a comma?» ) to point you in the right direction!
Conclusion
In this tutorial, you’ve seen what information the SyntaxError traceback gives you. You’ve also seen many common examples of invalid syntax in Python and what the solutions are to those problems. Not only will this speed up your workflow, but it will also make you a more helpful code reviewer!
When you’re writing code, try to use an IDE that understands Python syntax and provides feedback. If you put many of the invalid Python code examples from this tutorial into a good IDE, then they should highlight the problem lines before you even get to execute your code.
Getting a SyntaxError while you’re learning Python can be frustrating, but now you know how to understand traceback messages and what forms of invalid syntax in Python you might come up against. The next time you get a SyntaxError , you’ll be better equipped to fix the problem quickly!
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Identify Invalid Python Syntax
Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

About Chad Hansen
Chad is an avid Pythonista and does web development with Django fulltime. Chad lives in Utah with his wife and six kids.
Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:




Master Real-World Python Skills With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
Master Real-World Python Skills
With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
What Do You Think?
What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.
Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal. Looking for a real-time conversation? Visit the Real Python Community Chat or join the next “Office Hours” Live Q&A Session. Happy Pythoning!
SyntaxError: invalid syntax
It’s a sadly unhelpful error message and it’s one that you’ll see quite often when learning Python.
What does SyntaxError: invalid syntax mean? What is Python trying to tell you with this error and how can you fix your code to make Python happy?
What is a SyntaxError in Python?
This is Python’s way of saying «I don’t understand you». Python knows that what you’ve typed isn’t valid Python code but it’s not sure what advice to give you.
When you’re lucky, your SyntaxError will have some helpful advice in it:
But if you’re unlucky, you’ll see the message invalid syntax with nothing more:
This error message gives us no hints as to what might be going on outside of a line number and a bit of highlighting indicating where Python thinks the error occurred.
Causes of SyntaxError: invalid syntax
What are the likely causes of this mysterious error message?
When my Python students hit this error, the most likely causes are typically:
- Missing a colon ( : ) at the end of a line or mixing up other symbols
- Missing opening or closing parentheses ( ( . ) ), brackets ( [ . ] ), braces ( < . >), or quotes ( » . » ) or mistyping syntax within a block or expression
- Attempting to use a reserved keyword as a variable name code or other whitespace errors
- Treating statements like expressions
- Copying Python code into the REPL or copying from the REPL into a Python file
That’s a lot of options and they’re not the only options. How should you approach fixing this problem?
Fixing SyntaxError: invalid syntax
The first step in fixing SyntaxError s is narrowing down the problem.
I usually take the approach of:
- Note the line number and error message from the traceback, keeping in mind that both of these just guesses that Python’s making
- Working through the above list of common causes
- Attempting to read the code as Python would, looking for syntax mistakes
- Narrowing down the problem by removing blocks of code that I suspect may be the culprit
It’s easier to address that dreaded SyntaxError: invalid syntax exception when you’re familiar with its most common causes. Let’s attempt to build up our intuitions around SyntaxError: invalid syntax by touring the common causes of this error message.
Upgrading Python improves error messages
Before diving into specific errors, note that upgrading your Python version can drastically improve the helpfulness of common error messages.
Take this error message:
On Python 3.10 it looks considerably different:
We’re running the same square.py file in both cases:
But Python 3.10 showed a much more helpful message: the line number, the position, and the error message itself are all much clearer for many unclosed parentheses and braces on Python 3.10 and above.
The dreaded missing colon is another example. Any expression that starts a new block of code needs a : at the end.
Here’s the error that Python 3.9 shows for a missing colon:
And here’s the same error in Python 3.10:
Much more helpful, right? It’s still a SyntaxError exception, but the message is much clearer than simply invalid syntax .
Python 3.10 also includes friendlier error messages when you use = where you likely meant == :
Newer Python versions include more helpful error messages for missing commas, inline if expressions, unclosed braces/brackets/parentheses, and more.
If you have the ability to run your code on a newer version of Python, try it out. It might help you troubleshoot your syntax errors more effectively.
Count your parentheses
Forgetting closing parentheses, brackets, and braces is also a common source of coding errors.
Fortunately, recent Python versions have started noting unclosed brackets in their SyntaxError messages.
When running this code:
Python 3.9 used to show simply invalid syntax :
But Python 3.10 shows a more helpful error message:
But sometimes Python can get a little confused when guessing the cause of an error. Take this populate.py script:
When running this script, Python 3.10 shows this error message:
The problem is that all 3 of those write method calls are missing closing parentheses.
Count your parentheses!
Many code editors highlight matching parentheses, brackets, and braces (when your cursor is at an opening parentheses the closing one will change color). Use your code editor to see if each pair of parenthesis matches up properly (and that the one in matches seems correct).
Misspelled, missing, or misplaced keywords
Can you see what’s wrong with this line of code?
We were trying to define a function, but we misspelled def as drf . Python couldn’t figure out what we were trying to do, so it showed us that generic invalid syntax message.
What about this one?
Python’s pointing to the end of our comprehension and saying there’s a syntax error. But why?
Look a bit closer. There’s something missing in our comprehension.
We meant type this:
We were missing the in in our comprehension’s looping component.
Misspelled keywords and missing keywords often result in that mysterious invalid syntax , but extra keywords can cause trouble as well.
You can’t use reserved words as variable names in Python:
Python sees that word class and it assumes we’re defining a class. But then it sees an = sign and gets confused and can’t tell what we’re trying to do, so it throws its hands in the error and yells invalid syntax !
This one is a bit more mysterious:
That looks right, doesn’t it? So what’s the problem?
In Python the import . from syntax is actually a from . import syntax. We meant to write this instead:
Watch out for misspelled keywords, missing keywords, and re-arranged syntax. Also be sure not to use reserved words as variable names (e.g. class , return , and import are invalid variable names).
Subtle spacing problems
Can you see what’s wrong in this code?
Notice the extra space in the function name ( __init_ _ instead of __init__ )?
Can you identify what’s wrong in this line?
This one might be harder to spot.
Everything on that line is correct except that there’s no space between def and __init__ .
When one space character is valid, you can usually use more than one space character as well. But adding an extra space in the middle of an identifier or removing spaces where there should be spaces can often cause syntax errors.
Forgotten quotes and extra quotes
If you code infrequently, you likely forget to put quotes around your strings often. This is a very common mistake, so rest assured that you’re not alone!
Forgotten quotes can sometimes result in this cryptic invalid syntax error message:
Be careful with quotes within quotes:
You’ll need to switch to a different quote style (using double quotes for example) or escape those quotes.
Mixing up your symbols
Sometimes your syntax might look correct but you’ve actually confused one bit of syntax for another common bit of syntax.
That’s what happened here:
We’re trying to make a dictionary and we’ve accidentally used = instead of : to separate our key-value pairs.
Here’s another dictionary symbol mix up:
It looks like we’re trying to define a dictionary, but we started with an open square bracket ( [ ) instead of an open curly brace ( < ).
Another common syntax mistake is missing periods:
We’re trying to access the st_size attribute on the object returned from that path.stat() call, but we’ve forgot to put a . before st_size .
Sometimes syntax errors are due to characters being swapped around:
And some syntax errors are due to extra symbols you didn’t intend to write:
We wrote an extra . before our parentheses above.
Indentation errors in disguise
Sometimes a SyntaxError is actually an indentation error in disguise.
For example this code has an else clause that’s too far indented:
When we run the code we’ll see a SyntaxError :
Indentation issues often result in IndentationError exceptions, but sometimes they’ll manifest as SyntaxError exceptions instead.
Embedding statements within statements
A «statement» is either a block of Python code or a single line of Python code that can stand on its own.
An «expression» is a chunk of Python code that evaluates to a value. Expressions contain identifiers (i.e. variables), literals (e.g. [1, 2] , «hi» , and 4 ), and operators (e.g. + , in , and * ).
In Python we can embed one expression within another. But some expressions are actually «statements» which must be a line all on their own.
Here we’ve tried to embed one statement within another:
Assignments are statements in Python ( result = . is a statement). Python’s return is also a statement. We’ve tried to embed one statement inside another and Python didn’t understand us.
We likely meant either this:
Here’s the same issue with the global statement (see assigning to global variables):
And the same issue with the del statement:
If assignment is involved in your statement-inside-a-statement, an assignment expression (via Python’s walrus operator) may be helpful in resolving your issue. Though often the simplest solution is to split your code into multiple statements over multiple lines.
Errors that appear only in the Python REPL
Some errors are a bit less helpful within the Python REPL.
Take this invalid syntax error:
We’ll see that error within the Python REPL even on Python 3.11.
The issue is that the first line doesn’t have a closing parentheses. Python 3.10+ would properly point this out if we ran our code from a .py file instead:
But at the REPL Python doesn’t parse our code the same way (it parses block-by-block in the REPL) and sometimes error messages are a bit less helpful within the REPL as a result.
Here’s another REPL-specific error:
This is valid Python code:
But that can’t be copy-pasted directly into the REPL. In the Python REPL a blank line is needed after a block of code to end that block.
So we’d need to put a newline between the function definition and the function call:
Some errors are due to code that feels like it should work in a Python REPL but doesn’t. For example running python from within your Python REPL doesn’t work:
The above commands would work from our system command-prompt, but they don’t work within the Python REPL.
If you’re trying to launch Python or send a command to your prompt outside Python (like ls or dir ), you’ll need to do it from your system command prompt (Terminal, Powershell, Command Prompt, etc.). You can only type valid Python code from within the Python REPL.
Problems copy-pasting from the REPL
Copy-pasting from the Python REPL into a .py file will also result in syntax errors.
Here’s we’re running a file that has >>> prefixes before each line:
This isn’t a valid Python program:
But this is a valid Python program:
You’ll need to be careful about empty lines when copy-pasting from a .py file into a Python REPL and you’ll need to be careful about >>> and . prefixes and command output when copy-pasting from a REPL into a .py file.
The line number is just a «best guess»
It used to be that the line number for an error would usually represent the place that Python got confused about your syntax. That line number was often one or more lines after the actual error.
In recent versions of Python, the core developers have updated these line numbers in an attempt to make them more accurate.
For example here’s an error on Python 3.9 due to a missing comma:
And here’s the same error in Python 3.10:
Python’s given us a helpful hint on Python 3.10. But it’s also made a different guess about what line the error is on.
As you can see from the greet.py file, line 3 ( «Hello there» ) is the better guess in this case, as that’s where the comma is needed.
While deciphering tracebacks, keep in mind that the line number is just Python’s best guess as to where the error occurred.
SyntaxError exceptions happen all the time
If your code frequently results in SyntaxError exceptions, don’t fret. These kinds of exceptions happen all the time. When you’re newer to Python, you’ll find that it’s often a challenge to remember the exact syntax for the statements you’re writing.
But more experienced Python programmers also experience syntax errors. I make typos in my code quite often. I have a linter installed in my text editor to help me catch those typos though. I recommend searching for a «Python» or «Python linter» extension for your favorite code editor so you can spot these issues quickly every time you save your .py files.
Once you get past syntax errors, you’ll likely hit other types of exceptions. Watch the exception screencast series for more on reading tracebacks and exception handling in Python.
What comes after Intro to Python?
Intro to Python courses often skip over some fundamental Python concepts.
Sign up below and I’ll explain concepts that new Python programmers often overlook.
Intro to Python courses often skip over some fundamental Python concepts.
Sign up below and I’ll share ideas new Pythonistas often overlook.