
Errors When Asking AI to Write Python for Blender Are Two Types, and None Lies in Geometry
Errors when asking AI to write Python for Blender are two types, and none lies in geometry. First, Blender's API has changed since the time the AI model was trained, so the code looks right but runs wrong on the version you have. Second, the most serious errors of a 3D model are invisible when you render it: the image looks beautiful but the 3D printed object breaks. This post rewrites the troubleshooting process of @0xCodio (11/10/2026) in the order: pin the version, write straight into data instead of calling GUI operations, unify units, count geometry errors by code, then only let AI "see" the result. For example, one test of 1,190 answers shows the rate of runnable code drops from 91% to 70% when Blender upgrades to version 5.0.
This post is based on "Opus 5.5 Writes Blender Python for the Wrong Blender - and the Render Won't Tell You" by @0xCodio on X (11/10/2026), rewritten in English by OPCAIOS, condensed and explained. All benchmark numbers, software versions, and security information below are from the original author; OPCAIOS has not verified them independently; cross-check with current Blender documentation before applying to real work.

The loop in this post: each step has one machine check, only the "view 6 angles" step uses eyes (of AI). Diagram: OPCAIOS.
Two errors, not one
Error 1: What is AI aiming at the wrong Blender version?
Aiming at the wrong version is the situation where the AI model writes code for an old Blender while you run a new one. According to the author, one test ran 30 code-writing tasks on four Blender versions with ten models; each snippet was run for real in headless mode and had its own check; a total of 1,190 answers were graded. Results:
- Rate of code that runs: 91% on Blender 3.6, down to just 70% on Blender 5.0.
- Rate the model still says what has changed: from 81% down to 35%.
- Three task groups (compositor, boolean solver, sequencer) hit zero points across all models on Blender 5.0.
Clearest example: the identifier for the EEVEE renderer changed from BLENDER_EEVEE to BLENDER_EEVEE_NEXT in version 4.2, then back to BLENDER_EEVEE in version 5.0. A model that learned the right change midway now gets it wrong; a model that never learned it gets it right by accident. This is aiming off target, not reasoning failure.
Error 2: Why is geometry error invisible when rendering?
Invisible error is geometry error that ruins the 3D printable object but still gives a perfect render image. That is non-manifold edges, faces with zero area, parts cutting into each other, hollow cavities inside, and walls thinner than the printer nozzle. The author cites Blender's official MCP page, where Blender itself records that an AI model once missed a Solidify modifier that doubled the polygon count, because that modifier does not affect the view. So the human eye, or the eye of AI looking at a render image, is not enough to catch it: you need a counting step by code, described in Step 4 below.
Step 1: Pin the version before everything else
Pinning the version means declaring the target Blender and Python versions right in the prompt, then having the program prove it runs on those versions. According to @0xCodio (2026), the current release is Blender 5.2.2 LTS, and 4.5 is still maintained. Python moved from 3.11 to 3.13 in version 5.1, and the bpy package only runs correctly on one Python version — there's no such thing as "close enough". For example, every session working with Claude from Anthropic or ChatGPT from OpenAI should start with this system prompt template:
Target Blender 5.2 LTS, Python 3.13. Do not use any API removed before it.
Rules:
- bpy.data and bmesh only; no bpy.ops.mesh.* and no bpy.ops.object.*
except where I have named one
- one Blender unit is one metre; declare MM = 0.001 and use it
- every dimension, clearance and wall thickness is a named module-level
constant, never inline
- boolean solver is EXACT unless I state the inputs are manifold
- end the script with the census asserts, not with a render
- after the code, list every API you used that changed in 4.0 or later
and state which release you are targeting for each
What does version-pinning in a prompt mean and how do you run Blender?
The prompt above means: target Blender 5.2 LTS and Python 3.13; use only bpy.data and bmesh, do not call interface operations; one Blender unit is one metre and declare MM = 0.001; every dimension is a named constant; the boolean solver defaults to EXACT; end the script with counting checks instead of a render; finally, list every API that changed since 4.0 and which version you are targeting for each. Then run Blender headless with this command:
blender --background --factory-startup \
--python-exit-code 1 \
--python build.py -- --out ./dist --mm 20
Two details that have each cost people a full day:
- Missing
--python-exit-code: errors in the script won't change Blender's exit status, so automated test systems (CI) report green even though the script crashed. - Argument order matters: put
-oafter the.blendfilename, otherwise opening the file overwrites the output path. Everything after--is passed to Python viasys.argv.
Step 2: interface operations are only for people; scripts must write directly to data
Interface operations (operators, bpy.ops.*) are commands that simulate clicking the mouse, and according to Blender's own documentation, these operators don't take data as parameters, only return whether they succeeded or not, and when the run conditions aren't met they report RuntimeError: ... context is incorrect without saying why. Running headless with no interface, every bpy.ops.mesh.* command tries to find an edit mesh context that doesn't exist, according to Blender (2026) and @0xCodio.
So first, prompt the model to write directly to bpy.data and bmesh, for example when using Claude or ChatGPT. A sample code-generation prompt for a 20 mm detail:
Build the part described below as a single Python file.
<spec: outer dimensions, wall, clearances, holes, tolerance, export path>
Output the parameter block first as a table. I will assert against it.
The boolean solver is also a trap because the default is a trap: FLOAT is documented as "does not support overlapping geometry", MANIFOLD only works on closed mesh, while EXACT is the only one that survives messy input. Feeding geometry generated by AI to the default solver is not an error — it's documented behavior.
Step 3: Scale errors that slip through every review
Scale errors are size mistakes off by tens or hundreds of times that still get past reviews, usually because three facts about units pile up together. First, according to Blender, pick a unit convention once and state it clearly right at the start of your script (in 2026 it's still this way):
MM = 0.001 # 1 Blender unit = 1 metre, so a 20 mm detail is 0.02
Next, the author stresses the glTF case: the spec mandates metres, Y axis pointing up, and the exporter has no scale option, so one Blender unit goes out as exactly one metre.
Where do people misunderstand Blender units?
A block 20 mm on a side easily becomes 40 mm if you misread size=, so the "what people think vs. what's true" table below, according to the author, deserves to be taped to the checklist of every new Blender project in 2026. These three misunderstandings cost users many debug hours each time they show up:
| What people think | What's true |
|---|---|
primitive_cube_add() makes a unit cube |
Makes a cube 2 units on a side; size= is the whole edge length |
unit_settings.scale_length = 0.001 means "work in mm" |
Display only; geometry, physics, and file export ignore it |
| The file exporter carries your units along | STL and OBJ carry no units — you have to pass use_scene_unit or global_scale |
The author stresses the glTF case: the spec mandates metres, Y axis pointing up, and the exporter has no scale option — Blender units go out at a 1:1 ratio, so one unit is one metre. The "what people think — what's true" table, according to the author:
| What people think | What's true |
|---|---|
primitive_cube_add() makes a unit cube |
Makes a cube 2 units on a side; size= is the whole edge length |
unit_settings.scale_length = 0.001 means "work in mm" |
Display only; geometry, physics, and file export ignore it |
| The file exporter carries your units along | STL and OBJ carry no units — you have to pass use_scene_unit or global_scale |
Step 4: census the code to answer what renders never could
The author calls it "census": a block of code that runs at the end of the script to count invisible errors and stop the whole process if any show up.
import bmesh
bm = bmesh.new(); bm.from_mesh(obj.data)
nonmanifold = sum(1 for e in bm.edges if not e.is_manifold)
flipped = sum(1 for e in bm.edges if e.is_manifold and not e.is_contiguous)
loose = sum(1 for v in bm.verts if not v.link_faces)
degenerate = sum(1 for f in bm.faces if f.calc_area() <= 1e-4)
from mathutils.bvhtree import BVHTree
tree = BVHTree.FromBMesh(bm, epsilon=1e-5)
selfhit = len(tree.overlap(tree))
assert (nonmanifold, flipped, loose, degenerate, selfhit) == (0, 0, 0, 0, 0)
assert abs(obj.dimensions.x - 0.020) < 1e-5 # correct size as requested
This block checks: non-manifold edges, flipped face edges, loose vertices, degenerate faces, parts that self-intersect, and size matching the spec. The author describes the full check as eleven questions that a render image can never answer.
A few technical points worth remembering:
- Measure before you look. A common pitfall is
bpy.ops.object.modifier_apply(modifier="Boolean"); in non-interactive runs, the way to survive is to grab the computed mesh:dg = bpy.context.evaluated_depsgraph_get()thenobj.evaluated_get(dg).to_mesh(). - Outside Blender, the
trimeshlibrary has anis_volumeproperty — meaning the object is closed, face order is consistent, and normals point outward. Weaker isis_watertight, and volume only makes sense if the mesh is already solid. - The 3D-Print Toolbox no longer ships with Blender but is a community add-on, so automated runs must install it themselves. Default thresholds (minimum wall 1 mm, overhang 45°) match 3D printing consensus, but only hold true when one unit is one metre.
Step 5: loops and the prompts that control them
A loop is a sequence of a cached system block, a spec, one code generation, one headless run, one census, and one numerical patch. According to @0xCodio (2026), such a loop costs a few cents, while a Blender run costs only a few seconds. The price table is quoted for Anthropic's Opus 5.5, per 1 million tokens: input $4, output $20, cache read $0.20, batch run $2 for input and $10 for output. Check the current price table from the provider, as OPCAIOS has not verified these rates.
Build images to make a summary table, not to judge. Once the census step is past, create a composite of six orthographic views of the part and give it to the AI only to score the things geometry cannot say: proportion against stated dimensions, whether details sit where they should, parts that read as floating or fused, and anything that appears but the spec did not ask for. A sample critical prompt:
Six orthographic views of one part: front, back, left, right, top,
three-quarter. The census already passed, so do not comment on topology.
Judge only what geometry cannot: proportion against the stated dimensions,
whether features sit where the spec says, parts that read as floating or
fused, and anything present that the spec did not ask for.
List discrepancies against: <parameter table>
The practical way is to build the geometry offscreen using GPU instead of full render, compositing six named views into one image. Two constraints: Cycles cannot build into an offscreen viewport so use EEVEE or Workbench; and Blender 5.2 adds gpu.init() correctly to get GPU when running --background.
The last step is numerical patch, not asking the AI to rewrite the whole script:
Change constants in the parameter block only. Do not restructure, do not
rename, do not add geometry.
Apply exactly: <discrepancy list>
Return a diff.
About Blender's MCP
Blender's MCP is a server that lets AI control Blender, and per the author (2026) there is now an official MCP server from Blender Lab (add-on v1.0.3, Blender 5.1 and up), and their page warns itself that it will "run code generated by the model in Blender with no fence" and recommends a virtual machine. The community server has around 28.7 thousand stars on GitHub, talks over TCP on the local machine, no auth, no encryption, and once had a path traversal bug fixed in version 1.6.5. The author's conclusion: treat both as tools for a dev machine, not for a machine with real data. For example, if used with Anthropic's Claude Code, run it in a virtual machine. If you are new to MCP, read What is MCP? first.
When importing a model made by 3D AI
If the model comes from a 3D generative AI, audit it more closely, not less closely. Per the author, the 2026 trend has moved away from watertight geometry: TRELLIS.2 even advertises non-watertight geometry and open surfaces as a feature — suited to clothes, foliage, wrong for anything that will be printed. No paid model commits to watertight.
The script processing chain after import, in the right order: validity check → census → repair with bmesh.ops (remove_doubles, recalc_face_normals, holes_fill, dissolve_degenerate) → scale and orient → boolean → finally quadriflow_remesh or voxel_remesh if topology needs to be usable.
About the numbers in 3D print: four public guidelines contradict each other by a factor of two to three on nearly everything. Only four numbers at all agree — overhang angle 45°, smallest hole Ø2.0 mm, fit gap 0.5 mm, minimum wall around 1.0–1.2 mm. Pass those four numbers as named parameters, and leave everything else that is contested as arguments with default values. A hard constant correct for one printer is wrong for the next.
Summary
Two things stand between a script that looks done and an object that actually exists are: version pinning and code-based verification. They are not extra costs; they are why a loop that costs a few cents can be reliable. Applying this framework outside Blender is also right: declare your target environment clearly, let the machine check what the machine can check, and use only eyes (human or AI) for the part the machine cannot check.
Read more: AI writes code with wrong version; Claude Code (or programming agent) for people who don't know how to code.
Source: @0xCodio on X, 11/10/2026 — rewritten and condensed by OPCAIOS; figures, versions, prices and security information per original author, not independently verified.
Translated from Vietnamese with AI. Read the original.
Want to apply this in your business?
Book a free 30-minute call (Vietnam time, in English or Vietnamese).


