Skip to content

non-primitive cast error when using multiple key-value pairs in debug! macro inside async_trait #706

@xhermosilla

Description

@xhermosilla

Description

When using the debug! (or other log-level) macro with multiple key-value pairs, compilation fails with the following error:

error[E0605]: non-primitive cast: `&[(&'static str, Value<'_>); 2]` as `&[(&str, Value<'_>)]`

However, when only one key-value pair is used, or when no key-values are included, it compiles and runs correctly.

### Example

This compiles fine:

debug!(host = "localhost", "Deleting documents");

But adding an additional key-value pair causes a compilation error:

debug!(host = "localhost", version = "1.0.0"; "Deleting documents");

This produces:

error[E0605]: non-primitive cast: `&[(&'static str, Value<'_>); 2]` as `&[(&str, Value<'_>)]`

Context

This happens inside a function annotated with #[async_trait], but the same pattern works fine outside of async traits.
It seems related to how Rust infers lifetimes and array types in macro expansions involving slices of tuples.

The generated code from the macro expands roughly into:

&[("host", host_value), ("version", version_value)] as &[(&str, Value)]

which causes the compiler to reject the cast because the inferred array type has 'static keys (&'static str) but the target expects &str.

### Workaround

Replacing the slice construction inside the macro with this expression fixes the issue:

&vec![
    ($crate::__log_key!($key), $crate::__log_value!($key $(:$capture)* = $($value)*))
] as &[_],

Using a vec![] and taking a reference seems to allow proper type coercion to &[(&str, Value)].

### Possible Cause

This likely comes from a type coercion mismatch between:
• the fixed array literal ([ ... ]) which has a concrete type like [(&'static str, Value<'>); N],
• and the expected trait-bound type &[(&str, Value<'
>)].

The compiler disallows this cast because arrays of tuples with different lifetimes on the first element are not directly coercible to slices of tuples with more general lifetimes.

Using vec![] allows dynamic slice coercion at runtime and avoids this limitation.

## Environment

•	Rust version: 1.81.0
•	Crate: log (latest release at time of writing)
•	Feature: kv enabled
•	Context: using within #[async_trait] functions

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions