{"record":{"id":"e84f171e8e87b62a","repo":"BoundaryML/baml","slug":"timezoneoffset-from-duration-expected-duration-instance","errorCode":null,"errorMessage":"TimeZoneOffset.from_duration: expected Duration instance","messagePattern":"TimeZoneOffset\\.from_duration: expected Duration instance","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"baml_language/crates/bex_vm/src/package_baml/time.rs","lineNumber":449,"sourceCode":"        let mut out = String::new();\n        format_clock_into(\n            &mut out,\n            u8::try_from(ns / NANOS_PER_HOUR).expect(\"hour fits in u8\"),\n            u8::try_from(ns / NANOS_PER_MINUTE % 60).expect(\"minute fits in u8\"),\n            u8::try_from(ns / NANOS_PER_SECOND % 60).expect(\"second fits in u8\"),\n            u32::try_from(ns % NANOS_PER_SECOND).expect(\"subsecond fits in u32\"),\n        );\n        bex_str::BexStr::from(out)\n    }\n}\n\n#[allow(clippy::used_underscore_items)] // Autogenerated from private BAML fields\nimpl BamlClassTimeTimeZoneOffset for PackageBamlImpl {\n    fn from_duration(vm: &mut BexVm, duration: &Value) -> Result<Value, VmRustFnError> {\n        let nanos = {\n            let instance = vm\n                .as_instance(duration)\n                .expect(\"TimeZoneOffset.from_duration: expected Duration instance\");\n            view::time::Duration { instance }._nanoseconds()\n        };\n        let offset_ns = i64::try_from(&*nanos)\n            .ok()\n            .filter(|ns| ns.abs() <= MAX_TZ_OFFSET_NS)\n            .ok_or_else(|| {\n                invalid_argument(\n                    \"TimeZoneOffset out of range: must be within ±24 hours\".to_string(),\n                )\n            })?;\n        Ok(copy::time::TimeZoneOffset {\n            _nanoseconds: offset_ns,\n        }\n        .to_value(vm))\n    }\n}\n\nimpl BamlClassTimeZonedDateTime for PackageBamlImpl {","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bex_vm/src/package_baml/time.rs#L431-L467","documentation":"This panic occurs in TimeZoneOffset.from_duration when the argument is not a Duration object instance allocated by the VM. vm.as_instance().expect() panics for nulls, numbers, strings, or objects of any other class instead of returning an error.","triggerScenarios":"Calling TimeZoneOffset.from_duration() with a non-Duration value: an int of nanoseconds, a string like 'PT5H', null, or a PlainTime/other instance.","commonSituations":"Passing a raw nanosecond count or ISO-8601 duration string instead of a Duration instance; deserialized durations losing instance identity through JSON.","solutions":["Construct a Duration first (e.g. Duration.of_hours(5)) and pass that instance.","Parse strings with Duration.parse before conversion.","Type-check the argument before the call.","Report a bug if a real Duration instance triggers the panic."],"exampleFix":"// before\nTimeZoneOffset.from_duration(5 * 3600 * 1_000_000_000) // int, panics\n// after\nTimeZoneOffset.from_duration(Duration.of_hours(5))","handlingStrategy":"type-guard","validationCode":"fn is_duration(v: &Value, vm: &BexVm) -> bool {\n    vm.as_instance(v).map(|i| i.class() == \"Duration\").unwrap_or(false)\n}","typeGuard":"fn as_duration<'a>(vm: &'a BexVm, v: &Value) -> Option<InstanceRef<'a>> {\n    vm.as_instance(v).ok().filter(|i| i.class() == \"Duration\")\n}","tryCatchPattern":"// BAML side\nif v is Duration { TimeZoneOffset.from_duration(v) } else { Error(\"expected Duration\") }","preventionTips":["Pass Duration instances, not raw nanosecond ints or ISO strings.","Parse strings with Duration.parse first.","Re-hydrate Duration instances after JSON deserialization."],"tags":["rust","panic","type-mismatch","timezone"],"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"}