Errors in AI Python code
I have tried some coding agents, and I found they produce, while sometimes usable (as in “working”) code, they also make rookie mistakes. Here I just want to list some of the really stupid mistakes AI might do, while programming in Python
The candidates
The models I use are either free or even local. Actually I prefer working with local models, gives me a sense of how much horrible power and water usage I accumulate by using AI :)
So, without further ado, here’s the list:
- gemma4. Google made this freely available, but it is a weird one. When told to produce code you have to explicitly tell it to write files.
- qwen3.6. Chinese ripoff… uhm, “destillation” they call it, of Claude code. No idea which one. Quite capable but makes stupid mistakes (see below).
- opencode with the default model. Fast, usable code, can feel a bit like it’s taken over your machine, writing files, pushing, creating databases, starting and stopping services… not really my thing. So I usually tell it to only create code and leave version management and deployment to me.
- Claude code in free mode. I’m not paying several hundred dollars for the privilege of having my code be used for training. No. But anyway, Claude code is quite capable, but I wonder how far you even can get with Claude using free mode.
Code organization
Prepare to have a sad mess in your project. Prepare to not be able to find
even the most basic things without using grep -r.
One of the types of program I create myself are Django web applications, both with a web interface and an API.
But. I don’t expect to find this in my Python code:
except Exception:
pass
That’s a strict violation of at least one Python rule. As Aaron Digulla puts it on Stack Overflow: “The main problem here is that it ignores all and any error: Out of memory, CPU is burning, user wants to stop, program wants to exit, Jabberwocky is killing users.”
Using “Exception” is only mildly better (because eg. the user stopping the program is not an exception), but the main problem is the “pass”. It’s basically “Continue as if nothing happened”, and in all but very few exceptions (see what I did there?) that is a bad thing.
Next, consistent naming and structure. I know naming things is difficult, and for a program it is even more difficult, since it has no ground rules in the back of its head. Even with the coding guidelines written down in eg. Claude code’s “knowledge base” I wouldn’t count on AI doing the right thing.
releases_helper.py
middleware.py
powerdns.py
Why? What? One is a generic name. One is a functional name. And one is coupled to external software. No consistency at all.
Another example of horrible code organization:
def get_dnssec_info(domain):
"""
Get comprehensive DNSSEC info for a domain from PowerDNS API + live DNS.
Returns:
active (bool): Whether DNSSEC is enabled on the zone.
keys (list): Crypto keys from PowerDNS (id, type, active, algorithm, bits, dnskey, ds).
dnskey_raw (str): Raw DNSKEY records from live DNS.
ds_from_parent (list): DS records from parent zone (live query).
ds_from_pdns (list): DS records reported by PowerDNS.
ds_chain_ok (bool or None): Whether parent DS matches PowerDNS DS.
ksk_expiry (str or None): KSK retire date from PowerDNS timing or RRSIG.
"""
import dns.resolver
import dns.flags
import dns.exception
import dns.rdatatype
from datetime import datetime, timezone
Why import things there? Why not top-level? What is the point of this function being buried in the lower section of the powerdns.py file mentioned above? Especially since most of the information is not fetched through the PowerDNS API at all (just plain DNS lookups, as the import of dns.resolver and friends should indicate). The only place PowerDNS comes in is when comparing DNS lookups with what is actually in our PowerDNS instance.
Next, implementing canned solutions yourself. There are very few instances where you want to avoid using canned solutions. I had one AI (don’t remember if it was Qwen3.6 or something else) write part of a 2FA solution itself - includingh the middleware - while there are perfectly fine canned solutions (or, as Python calls it, wheels) where installation is done after providing a few changes to the settings and the user model. There is no point in reinventing the wheel (yes, that’s why they’re called that in the Python universe) every single time. Same goes for all the CSS and Javascript hacks when there are ready-made solutions (I’d even use tailwind, though it is overkill for most things I do) freely available. So why adding a style section to your base template or even writing a script tag there?
Example:
<link href="{% static 'css/darkly-bootstrap.min.css' %}" rel="stylesheet">
<style>
body { padding-top: 4.5rem; padding-bottom: 2rem; background-color: #1a1a1a; color: #e0e0e0; }
.card { background-color: #2b2b2b; border-color: #444; }
.card-header { background-color: #333; color: #e0e0e0; }
.card-body { color: #e0e0e0; }
.alert-warning { background-color: #4e3e00; border-color: #6e5e00; }
.card-body pre { background: #1e1e1e; padding: 0.5rem; color: #e0e0e0; }
.table { color: #e0e0e0; }
.form-label { color: #e0e0e0; }
textarea, input, select { background-color: #2b2b2b; color: #e0e0e0; border-color: #444; }
</style>
Why? The “darkly” theme (from bootswatch - highly recommend that site) already sets a lot of colours, why modify them at all?