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:

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:

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
// 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:

impl Serializer for UserSerializer {
    type Target = third_party::User;
    // ...
}

For a transparent holder, select the carrier serializer whose target is the exact field type:

#[fory(with = OptionSerializer<UserSerializer>)]
user: Option<third_party::User>

For an exact container field, a carrier serializer is also valid:

#[fory(with = VecSerializer<UserSerializer>)]
users: Vec<third_party::User>

Use recursive collection syntax when selecting an element, map child, or tuple position:

#[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:

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:

#[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:

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:

cargo expand --test mod $mod$::$file$ > expanded.rs

Running Tests

Run All Tests

cargo test --features tests

Run Specific Test

cargo test -p tests --test $test_file $test_method

Run Test with Debugging

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:

# 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 VariablePurpose
RUST_BACKTRACE=1Enable stack traces
FORY_PANIC_ON_ERROR=1Panic at error site for debugging
ENABLE_FORY_DEBUG_OUTPUT=1Print field-level read/write events

Related Topics