Repository: KittyCAD/modeling-app
Pull request #5844: fix not giving miette error in bindings
Author: login: jessfraz
Created: 2025-03-17T16:58:58Z | Merged: 2025-03-17T20:35:49Z

closes #5843

Linked issue #5843: [BUG] (kcl-python-bindings): Semantic error in @settings directive is missing context
### Describe the bug

From Slack: https://kittycadworkspace.slack.com/archives/C06P9L5MCUD/p1742229074132379

### Steps to Reproduce

```js
// Generated by Text-to-CAD: draw a water molecule

@settings(defaultLengthUnit = nm)

// Constants for the water molecule
oxygenRadius = 0.066 // Approximate radius of an oxygen atom
hydrogenRadius = 0.053 // Approximate radius of a hydrogen atom
oxygenHydrogenDistance = 0.096 // Approximate distance between oxygen and hydrogen atoms
bondAngle = 104.5 // Bond angle in degrees

// Function to create a sphere representing an atom
fn createAtom(center, radius) {
  return startSketchOn('XY')
    |> circle(center = center, radius = radius)
    |> extrude(length = radius * 2)
}

// Create the oxygen atom at the origin
oxygenAtom = createAtom([0, 0], oxygenRadius)

// Calculate the positions of the hydrogen atoms
hydrogenOffsetX = oxygenHydrogenDistance * cos(toRadians(bondAngle / 2))
hydrogenOffsetY = oxygenHydrogenDistance * sin(toRadians(bondAngle / 2))

// Create the hydrogen atoms
hydrogenAtom1 = createAtom([hydrogenOffsetX, hydrogenOffsetY], hydrogenRadius)
hydrogenAtom2 = createAtom([-hydrogenOffsetX, hydrogenOffsetY], hydrogenRadius)
```

```
semantic: KclErrorDetails { source_ranges: [SourceRange([52, 85, 0])], message: "Unexpected value for length units: `nm`; expected one of `mm`, `cm`, `m`, `in`, `ft`, `yd`" }
```

### Expected Behavior

Expect a miette style error message.

### Screenshots and Recordings

_No response_

### Desktop OS

All

### Browser

_No response_

### Version

zoo-kcl v0.3.48

### Additional Context

_No response_

Diff:
diff --git a/rust/kcl-lib/src/simulation_tests.rs b/rust/kcl-lib/src/simulation_tests.rs
index 1e459e00103..16d6bf29cd2 100644
--- a/rust/kcl-lib/src/simulation_tests.rs
+++ b/rust/kcl-lib/src/simulation_tests.rs
@@ -2245,3 +2245,24 @@ mod assembly_mixed_units_cubes {
         super::execute(TEST_NAME, true).await
     }
 }
+mod bad_units_in_annotation {
+    const TEST_NAME: &str = "bad_units_in_annotation";
+
+    /// Test parsing KCL.
+    #[test]
+    fn parse() {
+        super::parse(TEST_NAME)
+    }
+
+    /// Test that parsing and unparsing KCL produces the original KCL input.
+    #[test]
+    fn unparse() {
+        super::unparse(TEST_NAME)
+    }
+
+    /// Test that KCL is executed correctly.
+    #[tokio::test(flavor = "multi_thread")]
+    async fn kcl_test_execute() {
+        super::execute(TEST_NAME, true).await
+    }
+}
diff --git a/rust/kcl-lib/tests/bad_units_in_annotation/artifact_commands.snap b/rust/kcl-lib/tests/bad_units_in_annotation/artifact_commands.snap
new file mode 100644
index 00000000000..0a620912f7f
--- /dev/null
+++ b/rust/kcl-lib/tests/bad_units_in_annotation/artifact_commands.snap
@@ -0,0 +1,56 @@
+---
+source: kcl-lib/src/simulation_tests.rs
+description: Artifact commands bad_units_in_annotation.kcl
+---
+[
+  {
+    "cmdId": "[uuid]",
+    "range": [
+      0,
+      0,
+      0
+    ],
+    "command": {
+      "type": "edge_lines_visible",
+      "hidden": false
+    }
+  },
+  {
+    "cmdId": "[uuid]",
+    "range": [
+      0,
+      0,
+      0
+    ],
+    "command": {
+      "type": "set_scene_units",
+      "unit": "mm"
+    }
+  },
+  {
+    "cmdId": "[uuid]",
+    "range": [
+      0,
+      0,
+      0
+    ],
+    "command": {
+      "type": "object_visible",
+      "object_id": "[uuid]",
+      "hidden": true
+    }
+  },
+  {
+    "cmdId": "[uuid]",
+    "range": [
+      0,
+      0,
+      0
+    ],
+    "command": {
+      "type": "object_visible",
+      "object_id": "[uuid]",
+      "hidden": true
+    }
+  }
+]
diff --git a/rust/kcl-lib/tests/bad_units_in_annotation/artifact_graph_flowchart.snap b/rust/kcl-lib/tests/bad_units_in_annotation/artifact_graph_flowchart.snap
new file mode 100644
index 00000000000..beb49103a23
--- /dev/null
+++ b/rust/kcl-lib/tests/bad_units_in_annotation/artifact_graph_flowchart.snap
@@ -0,0 +1,6 @@
+---
+source: kcl-lib/src/simulation_tests.rs
+description: Artifact graph flowchart bad_units_in_annotation.kcl
+extension: md
+snapshot_kind: binary
+---
diff --git a/rust/kcl-lib/tests/bad_units_in_annotation/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/bad_units_in_annotation/artifact_graph_flowchart.snap.md
new file mode 100644
index 00000000000..13e53350976
--- /dev/null
+++ b/rust/kcl-lib/tests/bad_units_in_annotation/artifact_graph_flowchart.snap.md
@@ -0,0 +1,3 @@
+```mermaid
+flowchart LR
+```
diff --git a/rust/kcl-lib/tests/bad_units_in_annotation/ast.snap b/rust/kcl-lib/tests/bad_units_in_annotation/ast.snap
new file mode 100644
index 00000000000..1b97a1cd0b1
--- /dev/null
+++ b/rust/kcl-lib/tests/bad_units_in_annotation/ast.snap
@@ -0,0 +1,847 @@
+---
+source: kcl-lib/src/simulation_tests.rs
+description: Result of parsing bad_units_in_annotation.kcl
+---
+{
+  "Ok": {
+    "body": [
+      {
+        "declaration": {
+          "end": 143,
+          "id": {
+            "end": 135,
+            "name": "oxygenRadius",
+            "start": 123,
+            "type": "Identifier"
+          },
+          "init": {
+            "end": 143,
+            "raw": "0.066",
+            "start": 138,
+            "type": "Literal",
+            "type": "Literal",
+            "value": {
+              "value": 0.066,
+              "suffix": "None"
+            }
+          },
+          "start": 123,
+          "type": "VariableDeclarator"
+        },
+        "end": 143,
+        "kind": "const",
+        "start": 123,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 206,
+          "id": {
+            "end": 198,
+            "name": "hydrogenRadius",
+            "start": 184,
+            "type": "Identifier"
+          },
+          "init": {
+            "end": 206,
+            "raw": "0.053",
+            "start": 201,
+            "type": "Literal",
+            "type": "Literal",
+            "value": {
+              "value": 0.053,
+              "suffix": "None"
+            }
+          },
+          "start": 184,
+          "type": "VariableDeclarator"
+        },
+        "end": 206,
+        "kind": "const",
+        "start": 184,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 278,
+          "id": {
+            "end": 270,
+            "name": "oxygenHydrogenDistance",
+            "start": 248,
+            "type": "Identifier"
+          },
+          "init": {
+            "end": 278,
+            "raw": "0.096",
+            "start": 273,
+            "type": "Literal",
+            "type": "Literal",
+            "value": {
+              "value": 0.096,
+              "suffix": "None"
+            }
+          },
+          "start": 248,
+          "type": "VariableDeclarator"
+        },
+        "end": 278,
+        "kind": "const",
+        "start": 248,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 354,
+          "id": {
+            "end": 346,
+            "name": "bondAngle",
+            "start": 337,
+            "type": "Identifier"
+          },
+          "init": {
+            "end": 354,
+            "raw": "104.5",
+            "start": 349,
+            "type": "Literal",
+            "type": "Literal",
+            "value": {
+              "value": 104.5,
+              "suffix": "None"
+            }
+          },
+          "start": 337,
+          "type": "VariableDeclarator"
+        },
+        "end": 354,
+        "kind": "const",
+        "start": 337,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 580,
+          "id": {
+            "end": 447,
+            "name": "createAtom",
+            "start": 437,
+            "type": "Identifier"
+          },
+          "init": {
+            "body": {
+              "body": [
+                {
+                  "argument": {
+                    "body": [
+                      {
+                        "arguments": [
+                          {
+                            "end": 493,
+                            "raw": "'XY'",
+                            "start": 489,
+                            "type": "Literal",
+                            "type": "Literal",
+                            "value": "XY"
+                          }
+                        ],
+                        "callee": {
+                          "end": 488,
+                          "name": "startSketchOn",
+                          "start": 475,
+                          "type": "Identifier"
+                        },
+                        "end": 494,
+                        "start": 475,
+                        "type": "CallExpression",
+                        "type": "CallExpression"
+                      },
+                      {
+                        "arguments": [
+                          {
+                            "type": "LabeledArg",
+                            "label": {
+                              "end": 515,
+                              "name": "center",
+                              "start": 509,
+                              "type": "Identifier"
+                            },
+                            "arg": {
+                              "end": 524,
+                              "name": "center",
+                              "start": 518,
+                              "type": "Identifier",
+                              "type": "Identifier"
+                            }
+                          },
+                          {
+                            "type": "LabeledArg",
+                            "label": {
+                              "end": 532,
+                              "name": "radius",
+                              "start": 526,
+                              "type": "Identifier"
+                            },
+                            "arg": {
+                              "end": 541,
+                              "name": "radius",
+                              "start": 535,
+                              "type": "Identifier",
+                              "type": "Identifier"
+                            }
+                          }
+                        ],
+                        "callee": {
+                          "end": 508,
+                          "name": "circle",
+                          "start": 502,
+                          "type": "Identifier"
+                        },
+                        "end": 542,
+                        "start": 502,
+                        "type": "CallExpressionKw",
+                        "type": "CallExpressionKw",
+                        "unlabeled": null
+                      },
+                      {
+                        "arguments": [
+                          {
+                            "type": "LabeledArg",
+                            "label": {
+                              "end": 564,
+                              "name": "length",
+                              "start": 558,
+                              "type": "Identifier"
+                            },
+                            "arg": {
+                              "end": 577,
+                              "left": {
+                                "end": 573,
+                                "name": "radius",
+                                "start": 567,
+                                "type": "Identifier",
+                                "type": "Identifier"
+                              },
+                              "operator": "*",
+                              "right": {
+                                "end": 577,
+                                "raw": "2",
+                                "start": 576,
+                                "type": "Literal",
+                                "type": "Literal",
+                                "value": {
+                                  "value": 2.0,
+                                  "suffix": "None"
+                                }
+                              },
+                              "start": 567,
+                              "type": "BinaryExpression",
+                              "type": "BinaryExpression"
+                            }
+                          }
+                        ],
+                        "callee": {
+                          "end": 557,
+                          "name": "extrude",
+                          "start": 550,
+                          "type": "Identifier"
+                        },
+                        "end": 578,
+                        "start": 550,
+                        "type": "CallExpressionKw",
+                        "type": "CallExpressionKw",
+                        "unlabeled": null
+                      }
+                    ],
+                    "end": 578,
+                    "start": 475,
+                    "type": "PipeExpression",
+                    "type": "PipeExpression"
+                  },
+                  "end": 578,
+                  "start": 468,
+                  "type": "ReturnStatement",
+                  "type": "ReturnStatement"
+                }
+              ],
+              "end": 580,
+              "start": 464
+            },
+            "end": 580,
+            "params": [
+              {
+                "type": "Parameter",
+                "identifier": {
+                  "end": 454,
+                  "name": "center",
+                  "start": 448,
+                  "type": "Identifier"
+                }
+              },
+              {
+                "type": "Parameter",
+                "identifier": {
+                  "end": 462,
+                  "name": "radius",
+                  "start": 456,
+                  "type": "Identifier"
+                }
+              }
+            ],
+            "start": 447,
+            "type": "FunctionExpression",
+            "type": "FunctionExpression"
+          },
+          "start": 437,
+          "type": "VariableDeclarator"
+        },
+        "end": 580,
+        "kind": "fn",
+        "start": 434,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 667,
+          "id": {
+            "end": 632,
+            "name": "oxygenAtom",
+            "start": 622,
+            "type": "Identifier"
+          },
+          "init": {
+            "arguments": [
+              {
+                "elements": [
+                  {
+                    "end": 648,
+                    "raw": "0",
+                    "start": 647,
+                    "type": "Literal",
+                    "type": "Literal",
+                    "value": {
+                      "value": 0.0,
+                      "suffix": "None"
+                    }
+                  },
+                  {
+                    "end": 651,
+                    "raw": "0",
+                    "start": 650,
+                    "type": "Literal",
+                    "type": "Literal",
+                    "value": {
+                      "value": 0.0,
+                      "suffix": "None"
+                    }
+                  }
+                ],
+                "end": 652,
+                "start": 646,
+                "type": "ArrayExpression",
+                "type": "ArrayExpression"
+              },
+              {
+                "end": 666,
+                "name": "oxygenRadius",
+                "start": 654,
+                "type": "Identifier",
+                "type": "Identifier"
+              }
+            ],
+            "callee": {
+              "end": 645,
+              "name": "createAtom",
+              "start": 635,
+              "type": "Identifier"
+            },
+            "end": 667,
+            "start": 635,
+            "type": "CallExpression",
+            "type": "CallExpression"
+          },
+          "start": 622,
+          "type": "VariableDeclarator"
+        },
+        "end": 667,
+        "kind": "const",
+        "start": 622,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 790,
+          "id": {
+            "end": 733,
+            "name": "hydrogenOffsetX",
+            "start": 718,
+            "type": "Identifier"
+          },
+          "init": {
+            "end": 790,
+            "left": {
+              "end": 758,
+              "name": "oxygenHydrogenDistance",
+              "start": 736,
+              "type": "Identifier",
+              "type": "Identifier"
+            },
+            "operator": "*",
+            "right": {
+              "arguments": [
+                {
+                  "arguments": [
+                    {
+                      "end": 788,
+                      "left": {
+                        "end": 784,
+                        "name": "bondAngle",
+                        "start": 775,
+                        "type": "Identifier",
+                        "type": "Identifier"
+                      },
+                      "operator": "/",
+                      "right": {
+                        "end": 788,
+                        "raw": "2",
+                        "start": 787,
+                        "type": "Literal",
+                        "type": "Literal",
+                        "value": {
+                          "value": 2.0,
+                          "suffix": "None"
+                        }
+                      },
+                      "start": 775,
+                      "type": "BinaryExpression",
+                      "type": "BinaryExpression"
+                    }
+                  ],
+                  "callee": {
+                    "end": 774,
+                    "name": "toRadians",
+                    "start": 765,
+                    "type": "Identifier"
+                  },
+                  "end": 789,
+                  "start": 765,
+                  "type": "CallExpression",
+                  "type": "CallExpression"
+                }
+              ],
+              "callee": {
+                "end": 764,
+                "name": "cos",
+                "start": 761,
+                "type": "Identifier"
+              },
+              "end": 790,
+              "start": 761,
+              "type": "CallExpression",
+              "type": "CallExpression"
+            },
+            "start": 736,
+            "type": "BinaryExpression",
+            "type": "BinaryExpression"
+          },
+          "start": 718,
+          "type": "VariableDeclarator"
+        },
+        "end": 790,
+        "kind": "const",
+        "start": 718,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 863,
+          "id": {
+            "end": 806,
+            "name": "hydrogenOffsetY",
+            "start": 791,
+            "type": "Identifier"
+          },
+          "init": {
+            "end": 863,
+            "left": {
+              "end": 831,
+              "name": "oxygenHydrogenDistance",
+              "start": 809,
+              "type": "Identifier",
+              "type": "Identifier"
+            },
+            "operator": "*",
+            "right": {
+              "arguments": [
+                {
+                  "arguments": [
+                    {
+                      "end": 861,
+                      "left": {
+                        "end": 857,
+                        "name": "bondAngle",
+                        "start": 848,
+                        "type": "Identifier",
+                        "type": "Identifier"
+                      },
+                      "operator": "/",
+                      "right": {
+                        "end": 861,
+                        "raw": "2",
+                        "start": 860,
+                        "type": "Literal",
+                        "type": "Literal",
+                        "value": {
+                          "value": 2.0,
+                          "suffix": "None"
+                        }
+                      },
+                      "start": 848,
+                      "type": "BinaryExpression",
+                      "type": "BinaryExpression"
+                    }
+                  ],
+                  "callee": {
+                    "end": 847,
+                    "name": "toRadians",
+                    "start": 838,
+                    "type": "Identifier"
+                  },
+                  "end": 862,
+                  "start": 838,
+                  "type": "CallExpression",
+                  "type": "CallExpression"
+                }
+              ],
+              "callee": {
+                "end": 837,
+                "name": "sin",
+                "start": 834,
+                "type": "Identifier"
+              },
+              "end": 863,
+              "start": 834,
+              "type": "CallExpression",
+              "type": "CallExpression"
+            },
+            "start": 809,
+            "type": "BinaryExpression",
+            "type": "BinaryExpression"
+          },
+          "start": 791,
+          "type": "VariableDeclarator"
+        },
+        "end": 863,
+        "kind": "const",
+        "start": 791,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 972,
+          "id": {
+            "end": 907,
+            "name": "hydrogenAtom1",
+            "start": 894,
+            "type": "Identifier"
+          },
+          "init": {
+            "arguments": [
+              {
+                "elements": [
+                  {
+                    "end": 937,
+                    "name": "hydrogenOffsetX",
+                    "start": 922,
+                    "type": "Identifier",
+                    "type": "Identifier"
+                  },
+                  {
+                    "end": 954,
+                    "name": "hydrogenOffsetY",
+                    "start": 939,
+                    "type": "Identifier",
+                    "type": "Identifier"
+                  }
+                ],
+                "end": 955,
+                "start": 921,
+                "type": "ArrayExpression",
+                "type": "ArrayExpression"
+              },
+              {
+                "end": 971,
+                "name": "hydrogenRadius",
+                "start": 957,
+                "type": "Identifier",
+                "type": "Identifier"
+              }
+            ],
+            "callee": {
+              "end": 920,
+              "name": "createAtom",
+              "start": 910,
+              "type": "Identifier"
+            },
+            "end": 972,
+            "start": 910,
+            "type": "CallExpression",
+            "type": "CallExpression"
+          },
+          "start": 894,
+          "type": "VariableDeclarator"
+        },
+        "end": 972,
+        "kind": "const",
+        "start": 894,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      },
+      {
+        "declaration": {
+          "end": 1052,
+          "id": {
+            "end": 986,
+            "name": "hydrogenAtom2",
+            "start": 973,
+            "type": "Identifier"
+          },
+          "init": {
+            "arguments": [
+              {
+                "elements": [
+                  {
+                    "argument": {
+                      "end": 1017,
+                      "name": "hydrogenOffsetX",
+                      "start": 1002,
+                      "type": "Identifier",
+                      "type": "Identifier"
+                    },
+                    "end": 1017,
+                    "operator": "-",
+                    "start": 1001,
+                    "type": "UnaryExpression",
+                    "type": "UnaryExpression"
+                  },
+                  {
+                    "end": 1034,
+                    "name": "hydrogenOffsetY",
+                    "start": 1019,
+                    "type": "Identifier",
+                    "type": "Identifier"
+                  }
+                ],
+                "end": 1035,
+                "start": 1000,
+                "type": "ArrayExpression",
+                "type": "ArrayExpression"
+              },
+              {
+                "end": 1051,
+                "name": "hydrogenRadius",
+                "start": 1037,
+                "type": "Identifier",
+                "type": "Identifier"
+              }
+            ],
+            "callee": {
+              "end": 999,
+              "name": "createAtom",
+              "start": 989,
+              "type": "Identifier"
+            },
+            "end": 1052,
+            "start": 989,
+            "type": "CallExpression",
+            "type": "CallExpression"
+          },
+          "start": 973,
+          "type": "VariableDeclarator"
+        },
+        "end": 1052,
+        "kind": "const",
+        "start": 973,
+        "type": "VariableDeclaration",
+        "type": "VariableDeclaration"
+      }
+    ],
+    "end": 1053,
+    "innerAttrs": [
+      {
+        "end": 33,
+        "name": {
+          "end": 9,
+          "name": "settings",
+          "start": 1,
+          "type": "Identifier"
+        },
+        "properties": [
+          {
+            "end": 32,
+            "key": {
+              "end": 27,
+              "name": "defaultLengthUnit",
+              "start": 10,
+              "type": "Identifier"
+            },
+            "start": 10,
+            "type": "ObjectProperty",
+            "value": {
+              "end": 32,
+              "name": "nm",
+              "start": 30,
+              "type": "Identifier",
+              "type": "Identifier"
+            }
+          }
+        ],
+        "start": 0,
+        "type": "Annotation"
+      }
+    ],
+    "nonCodeMeta": {
+      "nonCodeNodes": {
+        "0": [
+          {
+            "end": 183,
+            "start": 143,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "inlineComment",
+              "value": "Approximate radius of an oxygen atom",
+              "style": "line"
+            }
+          }
+        ],
+        "1": [
+          {
+            "end": 247,
+            "start": 206,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "inlineComment",
+              "value": "Approximate radius of a hydrogen atom",
+              "style": "line"
+            }
+          }
+        ],
+        "2": [
+          {
+            "end": 336,
+            "start": 278,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "inlineComment",
+              "value": "Approximate distance between oxygen and hydrogen atoms",
+              "style": "line"
+            }
+          }
+        ],
+        "3": [
+          {
+            "end": 379,
+            "start": 354,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "inlineComment",
+              "value": "Bond angle in degrees",
+              "style": "line"
+            }
+          },
+          {
+            "end": 382,
+            "start": 379,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "newLine"
+            }
+          },
+          {
+            "end": 433,
+            "start": 382,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "blockComment",
+              "value": "Function to create a sphere representing an atom",
+              "style": "line"
+            }
+          }
+        ],
+        "4": [
+          {
+            "end": 621,
+            "start": 580,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "newLineBlockComment",
+              "value": "Create the oxygen atom at the origin",
+              "style": "line"
+            }
+          }
+        ],
+        "5": [
+          {
+            "end": 717,
+            "start": 667,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "newLineBlockComment",
+              "value": "Calculate the positions of the hydrogen atoms",
+              "style": "line"
+            }
+          }
+        ],
+        "7": [
+          {
+            "end": 893,
+            "start": 863,
+            "type": "NonCodeNode",
+            "value": {
+              "type": "newLineBlockComment",
+              "value": "Create the hydrogen atoms",
+              "style": "line"
+            }
+          }
+        ]
+      },
+      "startNodes": [
+        {
+          "end": 84,
+          "start": 34,
+          "type": "NonCodeNode",
+          "value": {
+            "type": "blockComment",
+            "value": "Generated by Text-to-CAD: draw a water molecule",
+            "style": "line"
+          }
+        },
+        {
+          "end": 87,
+          "start": 84,
+          "type": "NonCodeNode",
+          "value": {
+            "type": "newLine"
+          }
+        },
+        {
+          "end": 122,
+          "start": 87,
+          "type": "NonCodeNode",
+          "value": {
+            "type": "blockComment",
+            "value": "Constants for the water molecule",
+            "style": "line"
+          }
+        }
+      ]
+    },
+    "start": 0
+  }
+}
diff --git a/rust/kcl-lib/tests/bad_units_in_annotation/execution_error.snap b/rust/kcl-lib/tests/bad_units_in_annotation/execution_error.snap
new file mode 100644
index 00000000000..1978cac59da
--- /dev/null
+++ b/rust/kcl-lib/tests/bad_units_in_annotation/execution_error.snap
@@ -0,0 +1,14 @@
+---
+source: kcl-lib/src/simulation_tests.rs
+description: Error from executing bad_units_in_annotation.kcl
+---
+KCL Semantic error
+
+  × semantic: Unexpected value for length units: `nm`; expected one of `mm`,
+  │ `cm`, `m`, `in`, `ft`, `yd`
+   ╭─[1:1]
+ 1 │ @settings(defaultLengthUnit = nm)
+   · ────────────────┬────────────────
+   ·                 ╰── tests/bad_units_in_annotation/input.kcl
+ 2 │ // Generated by Text-to-CAD: draw a water molecule
+   ╰────
diff --git a/rust/kcl-lib/tests/bad_units_in_annotation/input.kcl b/rust/kcl-lib/tests/bad_units_in_annotation/input.kcl
new file mode 100644
index 00000000000..ea567d76170
--- /dev/null
+++ b/rust/kcl-lib/tests/bad_units_in_annotation/input.kcl
@@ -0,0 +1,28 @@
+@settings(defaultLengthUnit = nm)
+// Generated by Text-to-CAD: draw a water molecule
+
+
+// Constants for the water molecule
+oxygenRadius = 0.066 // Approximate radius of an oxygen atom
+hydrogenRadius = 0.053 // Approximate radius of a hydrogen atom
+oxygenHydrogenDistance = 0.096 // Approximate distance between oxygen and hydrogen atoms
+bondAngle = 104.5 // Bond angle in degrees
+
+
+// Function to create a sphere representing an atom
+fn createAtom(center, radius) {
+  return startSketchOn('XY')
+    |> circle(center = center, radius = radius)
+    |> extrude(length = radius * 2)
+}
+
+// Create the oxygen atom at the origin
+oxygenAtom = createAtom([0, 0], oxygenRadius)
+
+// Calculate the positions of the hydrogen atoms
+hydrogenOffsetX = oxygenHydrogenDistance * cos(toRadians(bondAngle / 2))
+hydrogenOffsetY = oxygenHydrogenDistance * sin(toRadians(bondAngle / 2))
+
+// Create the hydrogen atoms
+hydrogenAtom1 = createAtom([hydrogenOffsetX, hydrogenOffsetY], hydrogenRadius)
+hydrogenAtom2 = createAtom([-hydrogenOffsetX, hydrogenOffsetY], hydrogenRadius)
diff --git a/rust/kcl-lib/tests/bad_units_in_annotation/ops.snap b/rust/kcl-lib/tests/bad_units_in_annotation/ops.snap
new file mode 100644
index 00000000000..33d0ac85b7e
--- /dev/null
+++ b/rust/kcl-lib/tests/bad_units_in_annotation/ops.snap
@@ -0,0 +1,5 @@
+---
+source: kcl-lib/src/simulation_tests.rs
+description: Operations executed bad_units_in_annotation.kcl
+---
+[]
diff --git a/rust/kcl-python-bindings/src/lib.rs b/rust/kcl-python-bindings/src/lib.rs
index 6a2c0cc5387..ba0f6685a2a 100644
--- a/rust/kcl-python-bindings/src/lib.rs
+++ b/rust/kcl-python-bindings/src/lib.rs
@@ -401,10 +401,8 @@ async fn execute_and_export(path: String, export_format: FileExportFormat) -> Py
                 .map_err(|err| pyo3::exceptions::PyException::new_err(err.to_string()))?;
             let program = kcl_lib::Program::parse_no_errs(&code)
                 .map_err(|err| into_miette_for_parse(&path.display().to_string(), &code, err))?;
-            let settings = program.meta_settings()?.unwrap_or_default();
-            let units: UnitLength = settings.default_length_units.into();
 
-            let (ctx, mut state) = new_context_state(Some(path))
+            let (ctx, mut state) = new_context_state(Some(path.clone()))
                 .await
                 .map_err(|err| pyo3::exceptions::PyException::new_err(err.to_string()))?;
             // Execute the program.
@@ -412,6 +410,12 @@ async fn execute_and_export(path: String, export_format: FileExportFormat) -> Py
                 .await
                 .map_err(|err| into_miette(err, &code))?;
 
+            let settings = program
+                .meta_settings()
+                .map_err(|err| into_miette_for_parse(&path.display().to_string(), &code, err))?
+                .unwrap_or_default();
+            let units: UnitLength = settings.default_length_units.into();
+
             // This will not return until there are files.
             let resp = ctx
                 .engine
@@ -445,8 +449,6 @@ async fn execute_code_and_export(code: String, export_format: FileExportFormat)
         .spawn(async move {
             let program =
                 kcl_lib::Program::parse_no_errs(&code).map_err(|err| into_miette_for_parse("", &code, err))?;
-            let settings = program.meta_settings()?.unwrap_or_default();
-            let units: UnitLength = settings.default_length_units.into();
 
             let (ctx, mut state) = new_context_state(None)
                 .await
@@ -456,6 +458,12 @@ async fn execute_code_and_export(code: String, export_format: FileExportFormat)
                 .await
                 .map_err(|err| into_miette(err, &code))?;
 
+            let settings = program
+                .meta_settings()
+                .map_err(|err| into_miette_for_parse("", &code, err))?
+                .unwrap_or_default();
+            let units: UnitLength = settings.default_length_units.into();
+
             // This will not return until there are files.
             let resp = ctx
                 .engine
diff --git a/rust/kcl-python-bindings/tests/tests.py b/rust/kcl-python-bindings/tests/tests.py
index ad013e2aeac..5dba675deca 100755
--- a/rust/kcl-python-bindings/tests/tests.py
+++ b/rust/kcl-python-bindings/tests/tests.py
@@ -9,6 +9,7 @@
 kcl_dir = os.path.join(
     os.path.dirname(os.path.realpath(__file__)), "..", "..", "kcl-lib"
 )
+tests_dir = os.path.join(kcl_dir, "tests")
 lego_file = os.path.join(kcl_dir, "e2e", "executor", "inputs", "lego.kcl")
 walkie_talkie_dir = os.path.join(
     os.path.dirname(os.path.realpath(__file__)),
@@ -146,3 +147,20 @@ def test_kcl_lint():
         finding_title = finding.title
         assert finding_title is not None
         assert len(finding_title) > 0
+
+
+@pytest.mark.asyncio
+async def test_kcl_execute_code_and_export_with_bad_units():
+    bad_units_file = os.path.join(tests_dir, "bad_units_in_annotation", "input.kcl")
+    # Read from a file.
+    with open(bad_units_file, "r") as f:
+        code = str(f.read())
+        assert code is not None
+        assert len(code) > 0
+        try:
+            await kcl.execute_code_and_export(code, kcl.FileExportFormat.Step)
+        except Exception as e:
+            assert e is not None
+            assert len(str(e)) > 0
+            print(e)
+            assert "[1:1]" in str(e)


Reviews:
user: login: greg-kcio
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T18:56:56Z
user: login: greg-kcio
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T18:57:24Z
user: login: jessfraz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T19:03:46Z

Review comments:
diff_hunk: @@ -0,0 +1,30 @@
+@settings(defaultLengthUnit = nm)
+// Generated by Text-to-CAD: draw a water molecule
+
+
path: rust/kcl-lib/tests/bad_units_in_annotation/input.kcl
user: login: greg-kcio
body: bad autoformat :(
created_at: 2025-03-17T18:56:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+@settings(defaultLengthUnit = nm)
+// Generated by Text-to-CAD: draw a water molecule
+
+
path: rust/kcl-lib/tests/bad_units_in_annotation/input.kcl
user: login: jessfraz
body: oh ya this time its fine since in tests
created_at: 2025-03-17T19:03:46Z
author_association: CONTRIBUTOR

PR comments:
user: login: qa-wolf[bot]
created_at: 2025-03-17T16:59:02Z
body: QA Wolf here! As you write new code it's important that your test coverage is keeping up.
[Click here to request test coverage for this PR!](https://app.qawolf.com/api/coverage-requests/new/eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJwdWxsUmVxdWVzdElkIjoiZnliN3BpODI3Z3Y4N3B0Y2htMHdybWFxb3ByIiwiaWF0IjoxNzQyMjMwNzQxLCJleHAiOjE3NDQ4MjI3NDF9.jX3kG0mXQYRXzxBJMaPqOaWH-dstf9pBARElP7y1Pgcj-LpiyYGBjYZYf-WeeXlWSjCJqXabCYKs7m6t3fwxJs_m8YqWd-OU4bL8LbsNj9aV7EiKMRt3HhKK71RnI_WnAMEbIpjJCeUwUciHBFfKxvLAoPj_NIT6338KFLO3fMV4XuiPsOzo3KqOqnTz90xsXo2tiW_zupmQ3ZDGR1ENKYkKj0kwSbhivtubaQyZyO1zarDN4-3aI9UBhDUbG7vb4uJpcwjkTW535N3E3mE7G7Pxi3FAXV95ZdRt33WYdVxjZ7DWeWfKi_2Kst9dmmPARSo_BhXiArKOf8ElU_rM9Q)
author_association: NONE
user: login: vercel[bot]
created_at: 2025-03-17T16:59:02Z
body: [vc]: #0KDxd3/juoc+VDSlwodRvfaTWSNMcEraNQIM8i/M4qY=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJtb2RlbGluZy1hcHAiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20va2l0dHljYWQvbW9kZWxpbmctYXBwL0JRN2pjQzFyZjk0Y05TMVJRVVZvd1I1QXJCc1MiLCJwcmV2aWV3VXJsIjoibW9kZWxpbmctYXBwLWdpdC01ODQzLWZpeC1weXRob24tZXJyb3JzLWtpdHR5Y2FkLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiREVQTE9ZRUQiLCJyb290RGlyZWN0b3J5IjpudWxsfV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Updated (UTC) |
| :--- | :----- | :------ | :------ |
| **modeling-app** | ✅ Ready ([Inspect](https://vercel.com/kittycad/modeling-app/BQ7jcC1rf94cNS1RQUVowR5ArBsS)) | [Visit Preview](https://modeling-app-git-5843-fix-python-errors-kittycad.vercel.app) | Mar 17, 2025 8:27pm |


author_association: NONE
user: login: codecov[bot]
created_at: 2025-03-17T20:27:21Z
body: ## [Codecov](https://app.codecov.io/gh/KittyCAD/modeling-app/pull/5844?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD) Report
Attention: Patch coverage is `45.00000%` with `11 lines` in your changes missing coverage. Please review.
> Project coverage is 85.74%. Comparing base [(`87ab8fe`)](https://app.codecov.io/gh/KittyCAD/modeling-app/commit/87ab8fe78d98e577ac7604b40ba0563062836daf?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD) to head [(`61bd1ef`)](https://app.codecov.io/gh/KittyCAD/modeling-app/commit/61bd1ef7b39e61dd8e205656e3c1c915f477bf7d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD).
> Report is 1 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/KittyCAD/modeling-app/pull/5844?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD) | Patch % | Lines |
|---|---|---|
| [rust/kcl-python-bindings/src/lib.rs](https://app.codecov.io/gh/KittyCAD/modeling-app/pull/5844?src=pr&el=tree&filepath=rust%2Fkcl-python-bindings%2Fsrc%2Flib.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD#diff-cnVzdC9rY2wtcHl0aG9uLWJpbmRpbmdzL3NyYy9saWIucnM=) | 0.00% | [11 Missing :warning: ](https://app.codecov.io/gh/KittyCAD/modeling-app/pull/5844?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #5844      +/-   ##
==========================================
+ Coverage   85.73%   85.74%   +0.01%     
==========================================
  Files         110      110              
  Lines       42671    42686      +15     
==========================================
+ Hits        36582    36600      +18     
+ Misses       6089     6086       -3     
```

| [Flag](https://app.codecov.io/gh/KittyCAD/modeling-app/pull/5844/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD) | Coverage Δ | |
|---|---|---|
| [rust](https://app.codecov.io/gh/KittyCAD/modeling-app/pull/5844/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD) | `85.74% <45.00%> (+0.01%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/KittyCAD/modeling-app/pull/5844?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=KittyCAD).

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- 📦 [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE
user: login: codspeed-hq[bot]
created_at: 2025-03-17T20:58:35Z
body: <!-- __CODSPEED_PERFORMANCE_REPORT_COMMENT__ -->
<!-- __CODSPEED_WALLTIME_PERFORMANCE_REPORT_COMMENT__ -->

## [CodSpeed Walltime Performance Report](https://codspeed.io/KittyCAD/modeling-app/branches/5843-fix-python-errors)

### Merging #5844 will **degrade performances by 11.02%**

<sub>Comparing <code>5843-fix-python-errors</code> (61bd1ef) with <code>main</code> (75a975b)</sub>


<details>
<summary>:warning: <b>Unknown Walltime execution environment detected</b></summary>

> Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.
>
> For the most accurate results, we recommend using [CodSpeed Macro Runners](https://docs.codspeed.io/instruments/walltime/): bare-metal machines fine-tuned for performance measurement consistency.

</details>

### Summary

`⚡ 2` improvements  
`❌ 1` regressions  
`✅ 83` untouched benchmarks  


> :warning: _Please fix the performance issues or [acknowledge them on CodSpeed](https://codspeed.io/KittyCAD/modeling-app/branches/5843-fix-python-errors)._

### Benchmarks breakdown

|     | Benchmark | `BASE` | `HEAD` | Change |
| --- | --------- | ----------------------- | ------------------- | ------ |
| ⚡ | `` execute_color-cube `` | 1.6 s | 1.4 s | +10.2% |
| ❌ | `` execute_mounting-plate `` | 1.4 s | 1.6 s | -11.02% |
| ⚡ | `` digest_mike_stress_test `` | 1.4 ms | 1.3 ms | +12.88% |

author_association: NONE