{"record":{"id":"de4c319c33402b5d","repo":"dbt-labs/dbt-core","slug":"invalid-serialized-time-precision","errorCode":null,"errorMessage":"invalid serialized time precision","messagePattern":"invalid serialized time precision","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-adapter/src/sql_types.rs","lineNumber":1069,"sourceCode":"\n        pub fn unwrap(self) -> TimePrecision {\n            match self {\n                IsTimestamp::No => panic!(\"Cannot unwrap IsTimestamp::No\"),\n                IsTimestamp::Yes(precision) => precision,\n            }\n        }\n    }\n\n    pub fn is_time(data_type: &DataType) -> IsTimestamp {\n        match data_type {\n            DataType::FixedSizeList(field, 1) if field.name().starts_with(\"time:\") => {\n                IsTimestamp::Yes(TimePrecision::new(\n                    field\n                        .name()\n                        .strip_prefix(\"time:\")\n                        .expect(\"string prefix checked\")\n                        .parse::<u8>()\n                        .expect(\"invalid serialized time precision\"),\n                ))\n            }\n            _ => IsTimestamp::No,\n        }\n    }\n\n    pub fn is_timestamp_ntz(data_type: &DataType) -> IsTimestamp {\n        match data_type {\n            DataType::FixedSizeList(field, 1) if field.name().starts_with(\"timestamp_ntz:\") => {\n                IsTimestamp::Yes(TimePrecision::new(\n                    field\n                        .name()\n                        .strip_prefix(\"timestamp_ntz:\")\n                        .expect(\"string prefix checked\")\n                        .parse::<u8>()\n                        .expect(\"invalid serialized timestamp precision\"),\n                ))\n            }","sourceCodeStart":1051,"sourceCodeEnd":1087,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-adapter/src/sql_types.rs#L1051-L1087","documentation":"This panic comes from `parse::<u8>().expect(\"invalid serialized time precision\")` in `is_time`. The library encodes time precision in Arrow field names as `time:<u8>` (e.g. `time:3` for millisecond); when the digits after the prefix fail to parse as u8 (or the value exceeds TimePrecision's bounds), the parse fails and the code panics. Unlike the prefix expect, this one IS reachable with malformed serialized data.","triggerScenarios":"Calling `is_time(&DataType::FixedSizeList(field, 1))` where `field.name()` matches `time:*` but the remainder is not a valid u8 — e.g. `time:abc`, `time:` (empty), `time:300`, `time:-1`, or `time:3.5`. Also triggered by fixture/IPC files whose field names were hand-edited or produced by an older/different serializer.","commonSituations":"Hand-crafted Arrow schemas in tests or recordings, schema files migrated between dbt versions where the precision encoding changed, corrupted round-tripped metadata, or someone writing `time:9`/`time:100` assuming arbitrary precision digits are allowed.","solutions":["Fix the Arrow field name so the precision suffix is a valid u8 within the supported range (0, 3, 6, or 9 — matching second/millisecond/microsecond/nanosecond).","Locate where the field name is serialized (search for \"time:\" writers / from-arrow conversions) and correct the encoder, not just the fixture.","If the offending data comes from an old recording or IPC fixture, regenerate it with the current dbt version instead of patching by hand.","For resilience, replace the expect with a parse that returns IsTimestamp::No or a descriptive error rather than panicking on malformed upstream metadata."],"exampleFix":"// before\n.parse::<u8>()\n.expect(\"invalid serialized time precision\"),\n// after\n.parse::<u8>().unwrap_or_else(|_| panic!(\n    \"invalid serialized time precision in field '{}' (expected 'time:<0|3|6|9>')\",\n    field.name()))","handlingStrategy":"validation","validationCode":"fn validate_time_field_name(name: &str) -> Result<u8, String> {\n    let prec = name.strip_prefix(\"time:\")\n        .ok_or_else(|| format!(\"missing 'time:' prefix: {name}\"))?;\n    prec.parse::<u8>().map_err(|e| format!(\"bad precision in '{name}': {e}\"))\n}\n// call before passing the DataType to is_time\nassert!(validate_time_field_name(field.name()).is_ok());","typeGuard":"fn well_formed_time_type(dt: &DataType) -> bool {\n    matches!(dt, DataType::FixedSizeList(f, 1)\n        if f.name().strip_prefix(\"time:\").is_some_and(|s| s.parse::<u8>().is_ok()))\n}","tryCatchPattern":"// panic cannot be caught in Rust; run the conversion in a subprocess/isolated test if untrusted schemas must be tolerated\nlet result = std::panic::catch_unwind(|| is_time(&data_type));","preventionTips":["Schema-check Arrow IPC/recordings on ingest: every time:* field must carry a u8-precision suffix.","Version-pin fixtures and recordings to the serializer that produced them.","Prefer precision values 0/3/6/9 matching Arrow TimeUnit; reject anything else early.","Regenerate, don't hand-edit, corrupted schema metadata."],"tags":["rust","panic","parse-error","arrow","serialization"],"backgroundTag":"invalid-argument-format","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}