{"record":{"id":"dbf8c8e902283e85","repo":"BoundaryML/baml","slug":"attempted-to-read-a-property-that-has-no-defined-type-this","errorCode":null,"errorMessage":"attempted to read a property that has no defined type, this is likely an internal bug","messagePattern":"attempted to read a property that has no defined type, this is likely an internal bug","errorType":"exception","errorClass":"BamlError","httpStatus":null,"severity":"error","filePath":"engine/language_client_python/src/types/type_builder.rs","lineNumber":265,"sourceCode":"}\n\n#[pymethods]\nimpl ClassPropertyBuilder {\n    pub fn r#type(&self, r#type: &FieldType) -> Self {\n        self.inner\n            .lock()\n            .unwrap()\n            .set_type(r#type.inner.lock().unwrap().clone());\n        self.inner.clone().into()\n    }\n\n    pub fn get_type(&self) -> PyResult<FieldType> {\n        self.inner\n            .lock()\n            .unwrap()\n            .r#type()\n            .map(FieldType::from)\n            .ok_or_else(|| BamlError::from_anyhow(anyhow::anyhow!(\n                \"attempted to read a property that has no defined type, this is likely an internal bug\"\n            )))\n    }\n\n    #[pyo3(signature = (alias = None))]\n    pub fn alias(&self, alias: Option<&str>) -> Self {\n        self.inner.lock().unwrap().with_meta(\n            \"alias\",\n            alias.map_or(baml_types::BamlValue::Null, |s| {\n                BamlValue::String(s.to_string())\n            }),\n        );\n        self.inner.clone().into()\n    }\n\n    #[pyo3(signature = (description = None))]\n    pub fn description(&self, description: Option<&str>) -> Self {\n        self.inner.lock().unwrap().with_meta(","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/language_client_python/src/types/type_builder.rs#L247-L283","documentation":"TypeBuilder's property wrapper `get_type()` reads the property's assigned type under a lock; if no type was ever set, BAML raises this anyhow error instead of returning None, flagging it as an internal invariant violation.","triggerScenarios":"Calling `.type()` on a TypeBuilder property (from tb.add_property(...)) before calling `.set_type(...)` on it, or after building with a property that never received a type.","commonSituations":"Dynamic client code that adds properties but forgets to assign a type, or conditionally sets types and then reads them on a path where the assignment never ran.","solutions":["Always call .set_type(...) on each property before using/reading it","Check that the code path that assigns the type actually executed","Pass the TypeBuilder to the client only after all properties are fully configured"],"exampleFix":"// before\nprop = tb.add_property('MyClass', 'score')\nprint(prop.type())\n// after\nprop = tb.add_property('MyClass', 'score')\nprop.set_type(tb.type_int())\nprint(prop.type())","handlingStrategy":"validation","validationCode":"# ruby/python: ensure every property got a type before use\nfor prop in tb.all_properties: assert prop.type is not None","typeGuard":null,"tryCatchPattern":"try:\n    t = prop.type()\nexcept Exception as e:\n    raise RuntimeError(f'Property {prop.name!r} has no type set') from e","preventionTips":["Always call set_type immediately after add_property","Build TypeBuilders in a helper that enforces type assignment","Only pass fully configured builders to the dynamic client"],"tags":["type-builder","internal","dynamic-client"],"backgroundTag":"internal-invariant-violation","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}