How to Fix "SyntaxError: invalid non-printable character" in Python
Copy-pasted code from ChatGPT, a website, or a PDF throws SyntaxError: invalid non-printable character U+00A0 — and you can't see anything wrong. Here's what that character is, why Python rejects it, and three ways to fix it in under a minute.
What the error actually means
Python's tokenizer only accepts a specific set of characters outside strings. U+00A0 is a non-breaking space — it renders exactly like a normal space (U+0020), but it's a different Unicode code point. When Python hits it outside a string literal, it refuses to tokenize the line:
SyntaxError: invalid non-printable character U+00A0 The same family of errors appears for other invisible characters:
| Code point | Character | Typical source |
|---|---|---|
| U+00A0 | Non-breaking space | Word processors, websites, chat apps |
| U+200B | Zero-width space | AI chat output, some pastes |
| U+201C / U+201D | Curly quotes | Word processors, AI drafts |
| U+2013 / U+2014 | En/em dash | Word processors, AI drafts |
| U+202A–U+202E | Bidi controls | Copied RTL text, rare |
The kicker: your editor displays them invisibly, the error points at a line that "looks fine," and retyping works only if you find the right line.
Fix 1 — Find the exact character (30 seconds)
Paste the failing code into a viewer that names each code point at its line and column. I built a free one that runs entirely in your browser — nothing is uploaded: the code paste cleaner. It highlights the invisible character at the exact caret position and swaps in the correct ASCII equivalent (regular space, straight quotes, plain dashes), then gives you clean code to copy back.
The companion invisible Unicode checker does the same for prose and shows every suspicious code point in the text — useful for AI-assisted drafts where you want to see everything hiding in there.
Fix 2 — Replace the character with Python itself
If you know it's U+00A0, a one-liner rewrites the whole file:
import pathlib p = pathlib.Path("script.py") p.write_text( p.read_text(encoding="utf-8").replace("\u00a0", " "), encoding="utf-8", ) For the broader family (curly quotes, dashes, zero-width), normalize explicitly:
import pathlib import unicodedata p = pathlib.Path("script.py") text = p.read_text(encoding="utf-8") replacements = { "\u00a0": " ", "\u200b": "", "\u201c": '"', "\u201d": '"', "\u2018": "'", "\u2019": "'", "\u2013": "-", "\u2014": "-", } for bad, good in replacements.items(): text = text.replace(bad, good) p.write_text(text, encoding="utf-8") unicodedata.normalize("NFKC", text) also converts many of these — but it's aggressive: it changes characters you may want kept (like full-width symbols), so check the diff after.
Fix 3 — Prevent it next time
- Retype, don't paste, code from chat interfaces and PDFs — or paste into a plain-text editor first (Notepad,
nano), then into your IDE - Configure your editor to reveal them: VS Code's
editor.renderWhitespace: "boundary"shows unusual spaces; searching with regex\u00A0finds them file-wide - Run a linter before executing:
ruffandflake8flag suspicious characters with the code point named, which is much clearer than Python's runtime error
Why this happens more with AI-assisted coding
When you copy code out of chat interfaces, the copy can carry the chat's formatting characters — non-breaking spaces between tokens, curly quotes in strings, occasionally zero-width characters between letters. The code looks right because every one of these renders invisibly or near-invisibly. The error is Python doing its job: refusing characters that were never legal in source code.
The fix is always the same: make the invisible visible, replace with the ASCII equivalent, keep the logic identical.
If you want the checker mentioned above: code-cleaner for syntax-breaking characters, and the npm CLI strip-invisible (npx strip-invisible --check script.py) if you'd rather stay in the terminal. Both free, no account.




