{"record":{"id":"b3bf7dd6e6559b98","repo":"BoundaryML/baml","slug":"plaindatetime-to-plain-time-expected-plaindatetime-instance","errorCode":null,"errorMessage":"PlainDateTime.to_plain_time: expected PlainDateTime instance","messagePattern":"PlainDateTime\\.to_plain_time: expected PlainDateTime instance","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"baml_language/crates/bex_vm/src/package_baml/time.rs","lineNumber":335,"sourceCode":"        };\n        let days = i128::try_from(&*civil)\n            .ok()\n            .map(|n| n.div_euclid(NANOS_PER_DAY))\n            .and_then(|d| i64::try_from(d).ok())\n            .ok_or_else(|| {\n                invalid_argument(\n                    \"PlainDateTime.to_plain_date: value is outside the supported year range\"\n                        .to_string(),\n                )\n            })?;\n        Ok(copy::time::PlainDate { _days: days }.to_value(vm))\n    }\n\n    fn to_plain_time(vm: &mut BexVm, plaindatetime: &Value) -> Value {\n        let civil = {\n            let instance = vm\n                .as_instance(plaindatetime)\n                .expect(\"PlainDateTime.to_plain_time: expected PlainDateTime instance\");\n            view::time::PlainDateTime { instance }._nanoseconds()\n        };\n        // Euclidean modulo one day is exact regardless of the bigint's\n        // magnitude or sign, and the result always fits in an i64.\n        let day = num_bigint::BigInt::from(NANOS_PER_DAY);\n        let time_ns = ((&*civil % &day) + &day) % &day;\n        let time_ns = i64::try_from(time_ns).expect(\"time-of-day fits in i64\");\n        copy::time::PlainTime {\n            _nanoseconds: time_ns,\n        }\n        .to_value(vm)\n    }\n\n    fn year(plaindatetime: &view::time::PlainDateTime<'_>) -> Result<i64, VmRustFnError> {\n        Ok(i64::from(\n            civil_datetime(&plaindatetime._nanoseconds(), \"PlainDateTime.year\")?.year(),\n        ))\n    }","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bex_vm/src/package_baml/time.rs#L317-L353","documentation":"This Rust panic occurs inside PlainDateTime.to_plain_time when the value passed is not an actual PlainDateTime object instance allocated by the VM. The implementation calls vm.as_instance() and .expect()s it to succeed; any other Value (null, number, string, plain object) trips the panic instead of returning a catchable error.","triggerScenarios":"Calling the BAML to_plain_time() method with a non-PlainDateTime argument: a null, an int, a string, a plain object, or a Zoned/PlainTime of another class.","commonSituations":"Passing a datetime that was deserialized as a string or struct instead of a PlainDateTime instance; calling the method on the wrong type after a refactor; JSON round-trips that lose instance identity.","solutions":["Pass only values produced by PlainDateTime construction APIs (constructors, parse, arithmetic results).","Check the value's type/class before calling to_plain_time().","If inputs come from user data, normalize strings via PlainDateTime.parse first.","Report a bug if a genuine PlainDateTime instance triggers this (instance table corruption)."],"exampleFix":"// before\nlet t = \"2024-01-01T10:00:00\".to_plain_time(); // string, panics\n// after\nlet t = PlainDateTime.parse(\"2024-01-01T10:00:00\").to_plain_time();","handlingStrategy":"type-guard","validationCode":"fn is_plain_datetime(v: &Value, vm: &BexVm) -> bool {\n    vm.as_instance(v).map(|i| i.class() == \"PlainDateTime\").unwrap_or(false)\n}","typeGuard":"fn as_plain_datetime<'a>(vm: &'a BexVm, v: &Value) -> Option<InstanceRef<'a>> {\n    vm.as_instance(v).ok().filter(|i| i.class() == \"PlainDateTime\")\n}","tryCatchPattern":"// BAML side: guard before call\nif v is PlainDateTime { v.to_plain_time() } else { Error(\"expected PlainDateTime\") }","preventionTips":["Always obtain PlainDateTime values from constructors or parse, never from raw JSON.","Add a type check before calling date/time conversion methods.","Keep datetimes as instances across serialization boundaries (or re-parse strings on load)."],"tags":["rust","panic","type-mismatch","datetime"],"backgroundTag":"type-mismatch","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}