blob: 3097dc1d9c6f9833734dd06be72eee5db8ccad88 [file] [view]
---
title: Troubleshooting
sidebar_position: 90
id: troubleshooting
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---
This page covers common issues and debugging techniques for Apache Fory Rust.
## Common Issues
### Type Registry Errors
**Error**: `TypeId ... not found in type_info registry`
**Cause**: The type was never registered with the current `Fory` instance.
**Solution**: Register the type before serialization:
```rust
let mut fory = Fory::default();
fory.register::<MyStruct>(100)?; // Register before use
```
Confirm that:
- Every concrete dynamic target is registered through the matching structural,
union, or custom serializer API.
- The same ID or name mapping is reused on the deserialize side.
For external-type serialization, register the selected external structural or
custom serializer, not its third-party target:
```rust
fory.register::<UserSerializer>(100)?;
```
Do not register `VecSerializer<UserSerializer>` or another carrier serializer.
Register `UserSerializer`, then use recursive `list`, `map`, or `tuple`
annotations at fields, or select the carrier serializer at a root.
### Type Mismatch Errors
**Cause**: Field types are incompatible or schema has changed.
**Solution**:
- Keep compatible mode enabled for schema evolution
- Ensure field types match across versions
```rust
// Remove any compatible(false) override from the peers.
let fory = Fory::builder()
// existing options
.build();
```
### External-Type Serialization Selection Errors
If derive reports that `with` targets the wrong type, verify that the selected
serializer declares the exact field target:
```rust
impl Serializer for UserSerializer {
type Target = third_party::User;
// ...
}
```
For a transparent holder, select the carrier serializer whose target is the
exact field type:
```rust
#[fory(with = OptionSerializer<UserSerializer>)]
user: Option<third_party::User>
```
For an exact container field, a carrier serializer is also valid:
```rust
#[fory(with = VecSerializer<UserSerializer>)]
users: Vec<third_party::User>
```
Use recursive collection syntax when selecting an element, map child, or tuple
position:
```rust
#[fory(list(element(with = UserSerializer)))]
users: Vec<third_party::User>
```
If registration fails only in xlang mode, check whether the external structural
serializer contains a native Rust enum variant with multiple fields. That shape
has no xlang UNION representation; use native mode or change the shared schema.
## Debugging Techniques
### Enable Panic on Error for Backtraces
Toggle `FORY_PANIC_ON_ERROR=1` alongside `RUST_BACKTRACE=1` to panic at the exact site an error is constructed:
```bash
RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1 cargo test --features tests
```
Reset the variable afterwards to avoid aborting user-facing code paths.
### Struct Field Tracing
Add the `#[fory(debug)]` attribute alongside `#[derive(ForyStruct)]` to emit hook invocations:
```rust
#[derive(ForyStruct)]
#[fory(debug)]
struct MyStruct {
field1: i32,
field2: String,
}
```
Once compiled with debug hooks, call these functions to plug in custom callbacks:
- `set_before_write_field_func`
- `set_after_write_field_func`
- `set_before_read_field_func`
- `set_after_read_field_func`
Use `reset_struct_debug_hooks()` when you want the defaults back.
### Lightweight Logging
Without custom hooks, enable `ENABLE_FORY_DEBUG_OUTPUT=1` to print field-level read/write events:
```bash
ENABLE_FORY_DEBUG_OUTPUT=1 cargo test --features tests
```
This is especially useful when investigating alignment or cursor mismatches.
### Inspect Generated Code
Use `cargo expand` to inspect code generated by Fory derive macros:
```bash
cargo expand --test mod $mod$::$file$ > expanded.rs
```
## Running Tests
### Run All Tests
```bash
cargo test --features tests
```
### Run Specific Test
```bash
cargo test -p tests --test $test_file $test_method
```
### Run Test with Debugging
```bash
RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1 ENABLE_FORY_DEBUG_OUTPUT=1 \
cargo test --test mod $dir$::$test_file::$test_method -- --nocapture
```
## Test-Time Hygiene
Some integration tests expect `FORY_PANIC_ON_ERROR` to remain unset. Export it only for focused debugging sessions:
```bash
# For specific debugging only
FORY_PANIC_ON_ERROR=1 cargo test -p tests --test specific_test -- --nocapture
# Normal test run (without panic on error)
cargo test --features tests
```
## Error Handling Best Practices
Prefer the static constructors on the facade `Error` type:
- `Error::type_mismatch`
- `Error::invalid_data`
- `Error::unknown`
This keeps diagnostics consistent and makes opt-in panics work correctly.
## Quick Reference
| Environment Variable | Purpose |
| ---------------------------- | ----------------------------------- |
| `RUST_BACKTRACE=1` | Enable stack traces |
| `FORY_PANIC_ON_ERROR=1` | Panic at error site for debugging |
| `ENABLE_FORY_DEBUG_OUTPUT=1` | Print field-level read/write events |
## Related Topics
- [Configuration](configuration.md) - Fory options
- [Type Registration](type-registration.md) - Registration best practices
- [Schema Evolution](schema-evolution.md) - Compatible mode
- [External-Type Serialization](external-types.md) - Field and root serializer selection