You hit SyntaxError: invalid decimal literal because Python saw something that looked like a number but broke the rules for how decimal literals must be written. A "decimal literal" is simply a number you type directly in code-like 42, 3.14, or 1_000. When the parser can't unambiguously recognize the digits, separators, and dots, it stops and raises this error before your program even runs.
Think of the Python parser like a meticulous accountant. If a character shows up where only digits are allowed, or an underscore is dangling at the end of a number, the ledger doesn't balance and the report is rejected. The good news? The fix is almost always a tiny edit-remove a stray character, add a missing operator, or rewrite the number in a valid format.
Most Common Causes (with Fixes)
Below are frequent patterns that trigger this error, plus the correct way to write them. Depending on your Python version, you may sometimes see a slightly different message (for example, about leading zeros), but the root issue is the same: the literal isn't a valid decimal number.
Problematic code | Why it breaks | Correct form |
---|---|---|
part = 01 |
Leading zeros aren't allowed for decimal integers. | part = 1 (or use 0o1 for octal) |
value = 1_000_ |
Trailing underscores in numbers are invalid. | value = 1_000 |
n = 1__000 |
Double underscores aren't allowed inside digits. | n = 1_000 |
pi = 3._1415 |
An underscore can't touch a decimal point. | pi = 3.1415 or pi = 3.141_5 |
size = 2MB |
Letters glued to digits make Python think the number continues. | size = 2 * MB (define MB = 1024 * 1024 ) |
1st_place = "Alice" |
Identifiers can't start with a digit; parser thinks it's a number. | first_place = "Alice" |
code = 12O |
Letter O is not zero; invalid numeric character. | code = 120 |
A Simple Checklist to Locate the Bug Faster
- Scan every number on the line the error references; pay special attention to underscores and decimal points.
- Remove any trailing underscores; replace double underscores with single ones.
- Separate numbers from units or identifiers using
*
,/
, or string concatenation-never write2MB
or60sec
. - Rename variables that start with digits; use
first
,v2
, orcount_2025
instead of1st
or2025count
. - Watch for look-alikes: swap the letter
O
for0
, andl
for1
where needed. - If you pasted code, retype suspicious numbers to eliminate hidden non-ASCII characters or non-breaking spaces.
Edge Cases That Surprise Even Pros
One subtle trap is copying values from documents or spreadsheets. Some editors add non-breaking spaces or Unicode digits that look identical to ASCII characters but aren't valid in Python numeric literals. Re-enter the number manually in your IDE and the error often vanishes.
Another gotcha is mixing locale conventions with Python syntax. Writing price = 12,99
doesn't cause this particular error; Python actually reads it as a tuple (12, 99)
. That won't crash parsing, but it will break your logic later. For decimals, always use a dot: 12.99
.
Finally, numeric separators (_
) are fantastic for readability-1_000_000
beats 1000000
-but they're picky about placement. Keep them between digits only; never at the start or end, never adjacent to a decimal point, and never doubled up.
Prevention Tips for Clean, Future-Proof Numbers
Adopt a small style guide for numbers in your codebase. Prefer constants for units (KB, MB, GB) and multiply: 5 * MB
is explicit and safe. Keep numbers and words separate-if you need labels, put them in strings ("5MB"
) or concatenate (f"{size}MB"
), but don't attach them to the numeric literal itself.
Use code review or linters to catch suspicious patterns. Tools like flake8 or ruff help enforce consistent numeric formatting and quickly flag identifiers that start with digits or literals with stray underscores. If your scripts also interact with external services or large-scale data collection, plan for clean boundary layers-rate limits, retries, and network hygiene. For reliable, geotargeted routing and stable connections when scraping APIs or testing across regions, solutions such as Proxys.io can simplify the networking side while you focus on fixing the logic.
Quick Fix Playbook: From Error to Execution
Let's turn the diagnosis into action. If the error points to a line like total = 1_000_
, delete the trailing underscore. If it's lat = 3._1415
, move the underscore away from the dot. When you see 2MB
, split it into 2 * MB
and define MB
once. If a variable name starts with a number, rename it. And when you suspect a paste artifact, retype the number and run again.
A few extra guardrails can save you from repeat headaches. Write small tests that parse or compute with your numeric inputs. Keep magic numbers to a minimum; promote them to named constants so they're easy to audit. And remember: when the parser complains, it's doing you a favor-it's catching an ambiguity before it turns into a harder-to-trace runtime bug.
With these patterns and fixes in hand, SyntaxError: invalid decimal literal becomes a two-minute clean-up instead of a mystery. Tighten your numeric style, let your tools spot the outliers, and you'll spend far more time shipping features than chasing punctuation.